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

Side by Side Diff: components/offline_pages/offline_page_model.cc

Issue 2011763005: Splits the OfflinePageModel into and interface and and implementation class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unittest 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/offline_pages/offline_page_model.h" 5 #include "components/offline_pages/offline_page_model.h"
6 6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/files/file_util.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/optional.h"
16 #include "base/rand_util.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/time/time.h"
21 #include "components/offline_pages/archive_manager.h"
22 #include "components/offline_pages/client_policy_controller.h"
23 #include "components/offline_pages/offline_page_item.h"
24 #include "components/offline_pages/offline_page_storage_manager.h"
25 #include "url/gurl.h" 7 #include "url/gurl.h"
26 8
27 using ArchiverResult = offline_pages::OfflinePageArchiver::ArchiverResult;
28
29 namespace offline_pages { 9 namespace offline_pages {
30 10
31 namespace {
32
33 // This enum is used in an UMA histogram. Hence the entries here shouldn't
34 // be deleted or re-ordered and new ones should be added to the end.
35 enum ClearAllStatus {
36 CLEAR_ALL_SUCCEEDED,
37 STORE_RESET_FAILED,
38 STORE_RELOAD_FAILED,
39
40 // NOTE: always keep this entry at the end.
41 CLEAR_ALL_STATUS_COUNT
42 };
43
44 // The maximum histogram size for the metrics that measure time between views of
45 // a given page.
46 const base::TimeDelta kMaxOpenedPageHistogramBucket =
47 base::TimeDelta::FromDays(90);
48
49 SavePageResult ToSavePageResult(ArchiverResult archiver_result) {
50 SavePageResult result;
51 switch (archiver_result) {
52 case ArchiverResult::SUCCESSFULLY_CREATED:
53 result = SavePageResult::SUCCESS;
54 break;
55 case ArchiverResult::ERROR_DEVICE_FULL:
56 result = SavePageResult::DEVICE_FULL;
57 break;
58 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE:
59 result = SavePageResult::CONTENT_UNAVAILABLE;
60 break;
61 case ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED:
62 result = SavePageResult::ARCHIVE_CREATION_FAILED;
63 break;
64 case ArchiverResult::ERROR_CANCELED:
65 result = SavePageResult::CANCELLED;
66 break;
67 case ArchiverResult::ERROR_SECURITY_CERTIFICATE:
68 result = SavePageResult::SECURITY_CERTIFICATE_ERROR;
69 break;
70 default:
71 NOTREACHED();
72 result = SavePageResult::CONTENT_UNAVAILABLE;
73 }
74 return result;
75 }
76
77 std::string AddHistogramSuffix(const ClientId& client_id,
78 const char* histogram_name) {
79 if (client_id.name_space.empty()) {
80 NOTREACHED();
81 return histogram_name;
82 }
83 std::string adjusted_histogram_name(histogram_name);
84 adjusted_histogram_name += ".";
85 adjusted_histogram_name += client_id.name_space;
86 return adjusted_histogram_name;
87 }
88
89 void ReportStorageHistogramsAfterSave(
90 const ArchiveManager::StorageStats& storage_stats) {
91 const int kMB = 1024 * 1024;
92 int free_disk_space_mb =
93 static_cast<int>(storage_stats.free_disk_space / kMB);
94 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.SavePage.FreeSpaceMB",
95 free_disk_space_mb, 1, 500000, 50);
96
97 int total_page_size_mb =
98 static_cast<int>(storage_stats.total_archives_size / kMB);
99 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb);
100 }
101
102 void ReportStorageHistogramsAfterDelete(
103 const ArchiveManager::StorageStats& storage_stats) {
104 const int kMB = 1024 * 1024;
105 int free_disk_space_mb =
106 static_cast<int>(storage_stats.free_disk_space / kMB);
107 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DeletePage.FreeSpaceMB",
108 free_disk_space_mb, 1, 500000, 50);
109
110 int total_page_size_mb =
111 static_cast<int>(storage_stats.total_archives_size / kMB);
112 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb);
113
114 if (storage_stats.free_disk_space > 0) {
115 int percentage_of_free = static_cast<int>(
116 1.0 * storage_stats.total_archives_size /
117 (storage_stats.total_archives_size + storage_stats.free_disk_space) *
118 100);
119 UMA_HISTOGRAM_PERCENTAGE(
120 "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace",
121 percentage_of_free);
122 }
123 }
124
125 } // namespace
126
127 // static 11 // static
128 bool OfflinePageModel::CanSavePage(const GURL& url) { 12 bool OfflinePageModel::CanSavePage(const GURL& url) {
129 return url.SchemeIsHTTPOrHTTPS(); 13 return url.SchemeIsHTTPOrHTTPS();
130 } 14 }
131 15
132 // protected 16 OfflinePageModel::OfflinePageModel() {}
133 OfflinePageModel::OfflinePageModel()
134 : is_loaded_(false), weak_ptr_factory_(this) {}
135 17
136 OfflinePageModel::OfflinePageModel( 18 OfflinePageModel::~OfflinePageModel() {}
137 std::unique_ptr<OfflinePageMetadataStore> store,
138 const base::FilePath& archives_dir,
139 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
140 : store_(std::move(store)),
141 archives_dir_(archives_dir),
142 is_loaded_(false),
143 policy_controller_(new ClientPolicyController()),
144 archive_manager_(new ArchiveManager(archives_dir, task_runner)),
145 weak_ptr_factory_(this) {
146 archive_manager_->EnsureArchivesDirCreated(
147 base::Bind(&OfflinePageModel::OnEnsureArchivesDirCreatedDone,
148 weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
149 }
150
151 OfflinePageModel::~OfflinePageModel() {
152 }
153
154 void OfflinePageModel::AddObserver(Observer* observer) {
155 observers_.AddObserver(observer);
156 }
157
158 void OfflinePageModel::RemoveObserver(Observer* observer) {
159 observers_.RemoveObserver(observer);
160 }
161
162 void OfflinePageModel::SavePage(const GURL& url,
163 const ClientId& client_id,
164 std::unique_ptr<OfflinePageArchiver> archiver,
165 const SavePageCallback& callback) {
166 DCHECK(is_loaded_);
167
168 // Skip saving the page that is not intended to be saved, like local file
169 // page.
170 if (url.is_valid() && !CanSavePage(url)) {
171 InformSavePageDone(callback, SavePageResult::SKIPPED, client_id,
172 kInvalidOfflineId);
173 return;
174 }
175
176 // The web contents is not available if archiver is not created and passed.
177 if (!archiver.get()) {
178 InformSavePageDone(callback, SavePageResult::CONTENT_UNAVAILABLE, client_id,
179 kInvalidOfflineId);
180 return;
181 }
182
183 int64_t offline_id = GenerateOfflineId();
184
185 archiver->CreateArchive(
186 archives_dir_,
187 offline_id,
188 base::Bind(&OfflinePageModel::OnCreateArchiveDone,
189 weak_ptr_factory_.GetWeakPtr(), url, offline_id,
190 client_id, base::Time::Now(), callback));
191 pending_archivers_.push_back(std::move(archiver));
192 }
193
194 void OfflinePageModel::MarkPageAccessed(int64_t offline_id) {
195 DCHECK(is_loaded_);
196 auto iter = offline_pages_.find(offline_id);
197 if (iter == offline_pages_.end())
198 return;
199
200 // Make a copy of the cached item and update it. The cached item should only
201 // be updated upon the successful store operation.
202 OfflinePageItem offline_page_item = iter->second;
203
204 base::Time now = base::Time::Now();
205 base::TimeDelta time_since_last_accessed =
206 now - offline_page_item.last_access_time;
207
208 // When the access account is still zero, the page is opened for the first
209 // time since its creation.
210 UMA_HISTOGRAM_CUSTOM_COUNTS(
211 AddHistogramSuffix(
212 offline_page_item.client_id,
213 (offline_page_item.access_count == 0) ?
214 "OfflinePages.FirstOpenSinceCreated" :
215 "OfflinePages.OpenSinceLastOpen").c_str(),
216 time_since_last_accessed.InMinutes(), 1,
217 kMaxOpenedPageHistogramBucket.InMinutes(), 50);
218
219 offline_page_item.last_access_time = now;
220 offline_page_item.access_count++;
221
222 store_->AddOrUpdateOfflinePage(
223 offline_page_item,
224 base::Bind(&OfflinePageModel::OnMarkPageAccesseDone,
225 weak_ptr_factory_.GetWeakPtr(), offline_page_item));
226 }
227
228 void OfflinePageModel::DeletePagesByOfflineId(
229 const std::vector<int64_t>& offline_ids,
230 const DeletePageCallback& callback) {
231 if (!is_loaded_) {
232 delayed_tasks_.push_back(
233 base::Bind(&OfflinePageModel::DoDeletePagesByOfflineId,
234 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
235
236 return;
237 }
238 DoDeletePagesByOfflineId(offline_ids, callback);
239 }
240
241 void OfflinePageModel::DoDeletePagesByOfflineId(
242 const std::vector<int64_t>& offline_ids,
243 const DeletePageCallback& callback) {
244 DCHECK(is_loaded_);
245
246 std::vector<base::FilePath> paths_to_delete;
247 for (const auto& offline_id : offline_ids) {
248 auto iter = offline_pages_.find(offline_id);
249 if (iter != offline_pages_.end()) {
250 paths_to_delete.push_back(iter->second.file_path);
251 }
252 }
253
254 if (paths_to_delete.empty()) {
255 InformDeletePageDone(callback, DeletePageResult::NOT_FOUND);
256 return;
257 }
258
259 archive_manager_->DeleteMultipleArchives(
260 paths_to_delete,
261 base::Bind(&OfflinePageModel::OnDeleteArchiveFilesDone,
262 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
263 }
264
265 void OfflinePageModel::ClearAll(const base::Closure& callback) {
266 DCHECK(is_loaded_);
267
268 std::vector<int64_t> offline_ids;
269 for (const auto& id_page_pair : offline_pages_)
270 offline_ids.push_back(id_page_pair.first);
271 DeletePagesByOfflineId(
272 offline_ids,
273 base::Bind(&OfflinePageModel::OnRemoveAllFilesDoneForClearAll,
274 weak_ptr_factory_.GetWeakPtr(), callback));
275 }
276
277 void OfflinePageModel::DeletePagesByURLPredicate(
278 const UrlPredicate& predicate,
279 const DeletePageCallback& callback) {
280 if (!is_loaded_) {
281 delayed_tasks_.push_back(
282 base::Bind(&OfflinePageModel::DoDeletePagesByURLPredicate,
283 weak_ptr_factory_.GetWeakPtr(), predicate, callback));
284
285 return;
286 }
287 DoDeletePagesByURLPredicate(predicate, callback);
288 }
289
290 void OfflinePageModel::DoDeletePagesByURLPredicate(
291 const UrlPredicate& predicate,
292 const DeletePageCallback& callback) {
293 DCHECK(is_loaded_);
294
295 std::vector<int64_t> offline_ids;
296 for (const auto& id_page_pair : offline_pages_) {
297 if (predicate.Run(id_page_pair.second.url))
298 offline_ids.push_back(id_page_pair.first);
299 }
300 DoDeletePagesByOfflineId(offline_ids, callback);
301 }
302
303 void OfflinePageModel::HasPages(const std::string& name_space,
304 const HasPagesCallback& callback) {
305 RunWhenLoaded(base::Bind(&OfflinePageModel::HasPagesAfterLoadDone,
306 weak_ptr_factory_.GetWeakPtr(), name_space,
307 callback));
308 }
309
310 void OfflinePageModel::HasPagesAfterLoadDone(
311 const std::string& name_space,
312 const HasPagesCallback& callback) const {
313 DCHECK(is_loaded_);
314
315 bool has_pages = false;
316
317 for (const auto& id_page_pair : offline_pages_) {
318 if (id_page_pair.second.client_id.name_space == name_space) {
319 has_pages = true;
320 break;
321 }
322 }
323
324 callback.Run(has_pages);
325 }
326
327 void OfflinePageModel::CheckPagesExistOffline(
328 const std::set<GURL>& urls,
329 const CheckPagesExistOfflineCallback& callback) {
330 RunWhenLoaded(
331 base::Bind(&OfflinePageModel::CheckPagesExistOfflineAfterLoadDone,
332 weak_ptr_factory_.GetWeakPtr(), urls, callback));
333 }
334
335 void OfflinePageModel::CheckPagesExistOfflineAfterLoadDone(
336 const std::set<GURL>& urls,
337 const CheckPagesExistOfflineCallback& callback) {
338 DCHECK(is_loaded_);
339 CheckPagesExistOfflineResult result;
340 for (const auto& id_page_pair : offline_pages_) {
341 auto iter = urls.find(id_page_pair.second.url);
342 if (iter != urls.end())
343 result.insert(*iter);
344 }
345 callback.Run(result);
346 }
347
348 void OfflinePageModel::GetAllPages(
349 const MultipleOfflinePageItemCallback& callback) {
350 RunWhenLoaded(base::Bind(&OfflinePageModel::GetAllPagesAfterLoadDone,
351 weak_ptr_factory_.GetWeakPtr(), callback));
352 }
353
354 void OfflinePageModel::GetAllPagesAfterLoadDone(
355 const MultipleOfflinePageItemCallback& callback) {
356 DCHECK(is_loaded_);
357
358 MultipleOfflinePageItemResult offline_pages;
359 for (const auto& id_page_pair : offline_pages_)
360 offline_pages.push_back(id_page_pair.second);
361
362 callback.Run(offline_pages);
363 }
364
365 void OfflinePageModel::GetOfflineIdsForClientId(
366 const ClientId& client_id,
367 const MultipleOfflineIdCallback& callback) {
368 RunWhenLoaded(
369 base::Bind(&OfflinePageModel::GetOfflineIdsForClientIdWhenLoadDone,
370 weak_ptr_factory_.GetWeakPtr(), client_id, callback));
371 }
372
373 void OfflinePageModel::GetOfflineIdsForClientIdWhenLoadDone(
374 const ClientId& client_id,
375 const MultipleOfflineIdCallback& callback) const {
376 callback.Run(MaybeGetOfflineIdsForClientId(client_id));
377 }
378
379 const std::vector<int64_t> OfflinePageModel::MaybeGetOfflineIdsForClientId(
380 const ClientId& client_id) const {
381 DCHECK(is_loaded_);
382 std::vector<int64_t> results;
383
384 // We want only all pages, including those marked for deletion.
385 // TODO(bburns): actually use an index rather than linear scan.
386 for (const auto& id_page_pair : offline_pages_) {
387 if (id_page_pair.second.client_id == client_id)
388 results.push_back(id_page_pair.second.offline_id);
389 }
390 return results;
391 }
392
393 void OfflinePageModel::GetPageByOfflineId(
394 int64_t offline_id,
395 const SingleOfflinePageItemCallback& callback) {
396 RunWhenLoaded(base::Bind(&OfflinePageModel::GetPageByOfflineIdWhenLoadDone,
397 weak_ptr_factory_.GetWeakPtr(), offline_id,
398 callback));
399 }
400
401 void OfflinePageModel::GetPageByOfflineIdWhenLoadDone(
402 int64_t offline_id,
403 const SingleOfflinePageItemCallback& callback) const {
404 SingleOfflinePageItemResult result;
405 const OfflinePageItem* match = MaybeGetPageByOfflineId(offline_id);
406 if (match != nullptr)
407 result = *match;
408 callback.Run(result);
409 }
410
411 const OfflinePageItem* OfflinePageModel::MaybeGetPageByOfflineId(
412 int64_t offline_id) const {
413 const auto iter = offline_pages_.find(offline_id);
414 return iter != offline_pages_.end() ? &(iter->second) : nullptr;
415 }
416
417 void OfflinePageModel::GetPageByOfflineURL(
418 const GURL& offline_url,
419 const SingleOfflinePageItemCallback& callback) {
420 RunWhenLoaded(base::Bind(&OfflinePageModel::GetPageByOfflineURLWhenLoadDone,
421 weak_ptr_factory_.GetWeakPtr(), offline_url,
422 callback));
423 }
424
425 void OfflinePageModel::GetPageByOfflineURLWhenLoadDone(
426 const GURL& offline_url,
427 const SingleOfflinePageItemCallback& callback) const {
428 base::Optional<OfflinePageItem> result;
429
430 for (const auto& id_page_pair : offline_pages_) {
431 if (id_page_pair.second.GetOfflineURL() == offline_url) {
432 callback.Run(base::make_optional(id_page_pair.second));
433 return;
434 }
435 }
436
437 callback.Run(base::nullopt);
438 }
439
440 const OfflinePageItem* OfflinePageModel::MaybeGetPageByOfflineURL(
441 const GURL& offline_url) const {
442 for (const auto& id_page_pair : offline_pages_) {
443 if (id_page_pair.second.GetOfflineURL() == offline_url)
444 return &(id_page_pair.second);
445 }
446 return nullptr;
447 }
448
449 void OfflinePageModel::GetBestPageForOnlineURL(
450 const GURL& online_url,
451 const SingleOfflinePageItemCallback callback) {
452 RunWhenLoaded(
453 base::Bind(&OfflinePageModel::GetBestPageForOnlineURLWhenLoadDone,
454 weak_ptr_factory_.GetWeakPtr(), online_url, callback));
455 }
456
457 void OfflinePageModel::GetBestPageForOnlineURLWhenLoadDone(
458 const GURL& online_url,
459 const SingleOfflinePageItemCallback& callback) const {
460 SingleOfflinePageItemResult result;
461
462 const OfflinePageItem* best_page = MaybeGetBestPageForOnlineURL(online_url);
463 if (best_page != nullptr)
464 result = *best_page;
465
466 callback.Run(result);
467 }
468
469 void OfflinePageModel::GetPagesByOnlineURL(
470 const GURL& online_url,
471 const MultipleOfflinePageItemCallback& callback) {
472 RunWhenLoaded(base::Bind(&OfflinePageModel::GetPagesByOnlineURLWhenLoadDone,
473 weak_ptr_factory_.GetWeakPtr(), online_url,
474 callback));
475 }
476
477 void OfflinePageModel::GetPagesByOnlineURLWhenLoadDone(
478 const GURL& online_url,
479 const MultipleOfflinePageItemCallback& callback) const {
480 std::vector<OfflinePageItem> result;
481
482 for (const auto& id_page_pair : offline_pages_) {
483 if (id_page_pair.second.url == online_url)
484 result.push_back(id_page_pair.second);
485 }
486
487 callback.Run(result);
488 }
489
490 const OfflinePageItem* OfflinePageModel::MaybeGetBestPageForOnlineURL(
491 const GURL& online_url) const {
492 const OfflinePageItem* result = nullptr;
493 for (const auto& id_page_pair : offline_pages_) {
494 if (id_page_pair.second.url == online_url) {
495 if (!result || id_page_pair.second.creation_time > result->creation_time)
496 result = &(id_page_pair.second);
497 }
498 }
499 return result;
500 }
501
502 void OfflinePageModel::CheckForExternalFileDeletion() {
503 DCHECK(is_loaded_);
504
505 archive_manager_->GetAllArchives(
506 base::Bind(&OfflinePageModel::ScanForMissingArchiveFiles,
507 weak_ptr_factory_.GetWeakPtr()));
508 }
509
510 void OfflinePageModel::ExpirePages(const std::vector<int64_t>& offline_ids,
511 const base::Time& expiration_time) {
512 for (int64_t offline_id : offline_ids) {
513 auto iter = offline_pages_.find(offline_id);
514 if (iter == offline_pages_.end())
515 continue;
516
517 OfflinePageItem offline_page = iter->second;
518 offline_page.expiration_time = expiration_time;
519
520 store_->AddOrUpdateOfflinePage(
521 offline_page, base::Bind(&OfflinePageModel::OnExpirePageDone,
522 weak_ptr_factory_.GetWeakPtr(), offline_id,
523 expiration_time));
524 }
525 }
526
527 void OfflinePageModel::OnExpirePageDone(int64_t offline_id,
528 const base::Time& expiration_time,
529 bool success) {
530 // TODO(romax): Report UMA about successful expiration.
531 if (success) {
532 auto iter = offline_pages_.find(offline_id);
533 if (iter != offline_pages_.end())
534 iter->second.expiration_time = expiration_time;
535 }
536 }
537
538 ClientPolicyController* OfflinePageModel::GetPolicyController() {
539 return policy_controller_.get();
540 }
541
542 OfflinePageMetadataStore* OfflinePageModel::GetStoreForTesting() {
543 return store_.get();
544 }
545
546 OfflinePageStorageManager* OfflinePageModel::GetStorageManager() {
547 return storage_manager_.get();
548 }
549
550 bool OfflinePageModel::is_loaded() const {
551 return is_loaded_;
552 }
553
554 void OfflinePageModel::OnCreateArchiveDone(const GURL& requested_url,
555 int64_t offline_id,
556 const ClientId& client_id,
557 const base::Time& start_time,
558 const SavePageCallback& callback,
559 OfflinePageArchiver* archiver,
560 ArchiverResult archiver_result,
561 const GURL& url,
562 const base::FilePath& file_path,
563 int64_t file_size) {
564 if (requested_url != url) {
565 DVLOG(1) << "Saved URL does not match requested URL.";
566 // TODO(fgorski): We have created an archive for a wrong URL. It should be
567 // deleted from here, once archiver has the right functionality.
568 InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED,
569 client_id, offline_id);
570 DeletePendingArchiver(archiver);
571 return;
572 }
573
574 if (archiver_result != ArchiverResult::SUCCESSFULLY_CREATED) {
575 SavePageResult result = ToSavePageResult(archiver_result);
576 InformSavePageDone(callback, result, client_id, offline_id);
577 DeletePendingArchiver(archiver);
578 return;
579 }
580 OfflinePageItem offline_page_item(url, offline_id, client_id, file_path,
581 file_size, start_time);
582 store_->AddOrUpdateOfflinePage(
583 offline_page_item,
584 base::Bind(&OfflinePageModel::OnAddOfflinePageDone,
585 weak_ptr_factory_.GetWeakPtr(), archiver, callback,
586 offline_page_item));
587 }
588
589 void OfflinePageModel::OnAddOfflinePageDone(OfflinePageArchiver* archiver,
590 const SavePageCallback& callback,
591 const OfflinePageItem& offline_page,
592 bool success) {
593 SavePageResult result;
594 if (success) {
595 offline_pages_[offline_page.offline_id] = offline_page;
596 result = SavePageResult::SUCCESS;
597 UMA_HISTOGRAM_TIMES(
598 AddHistogramSuffix(
599 offline_page.client_id, "OfflinePages.SavePageTime").c_str(),
600 base::Time::Now() - offline_page.creation_time);
601 // 50 buckets capped between 1Kb and 10Mb.
602 UMA_HISTOGRAM_COUNTS_10000(AddHistogramSuffix(
603 offline_page.client_id, "OfflinePages.PageSize").c_str(),
604 offline_page.file_size / 1024);
605 } else {
606 result = SavePageResult::STORE_FAILURE;
607 }
608 InformSavePageDone(callback, result, offline_page.client_id,
609 offline_page.offline_id);
610 DeletePendingArchiver(archiver);
611
612 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
613 }
614
615 void OfflinePageModel::OnMarkPageAccesseDone(
616 const OfflinePageItem& offline_page_item, bool success) {
617 // Update the item in the cache only upon success.
618 if (success)
619 offline_pages_[offline_page_item.offline_id] = offline_page_item;
620
621 // No need to fire OfflinePageModelChanged event since updating access info
622 // should not have any impact to the UI.
623 }
624
625 void OfflinePageModel::OnEnsureArchivesDirCreatedDone(
626 const base::TimeTicks& start_time) {
627 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime",
628 base::TimeTicks::Now() - start_time);
629
630 store_->Load(base::Bind(&OfflinePageModel::OnLoadDone,
631 weak_ptr_factory_.GetWeakPtr(), start_time));
632 }
633
634 void OfflinePageModel::OnLoadDone(
635 const base::TimeTicks& start_time,
636 OfflinePageMetadataStore::LoadStatus load_status,
637 const std::vector<OfflinePageItem>& offline_pages) {
638 DCHECK(!is_loaded_);
639 is_loaded_ = true;
640
641 // TODO(jianli): rebuild the store upon failure.
642
643 if (load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED)
644 CacheLoadedData(offline_pages);
645
646 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ConstructionToLoadedEventTime",
647 base::TimeTicks::Now() - start_time);
648
649 // Create Storage Manager.
650 storage_manager_.reset(new OfflinePageStorageManager(
651 this, GetPolicyController(), archive_manager_.get()));
652
653 // Run all the delayed tasks.
654 for (const auto& delayed_task : delayed_tasks_)
655 delayed_task.Run();
656 delayed_tasks_.clear();
657
658 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelLoaded(this));
659
660 CheckForExternalFileDeletion();
661 }
662
663 void OfflinePageModel::InformSavePageDone(const SavePageCallback& callback,
664 SavePageResult result,
665 const ClientId& client_id,
666 int64_t offline_id) {
667 UMA_HISTOGRAM_ENUMERATION(
668 AddHistogramSuffix(client_id, "OfflinePages.SavePageResult").c_str(),
669 static_cast<int>(result),
670 static_cast<int>(SavePageResult::RESULT_COUNT));
671 archive_manager_->GetStorageStats(
672 base::Bind(&ReportStorageHistogramsAfterSave));
673 callback.Run(result, offline_id);
674 }
675
676 void OfflinePageModel::DeletePendingArchiver(OfflinePageArchiver* archiver) {
677 pending_archivers_.erase(std::find(
678 pending_archivers_.begin(), pending_archivers_.end(), archiver));
679 }
680
681 void OfflinePageModel::OnDeleteArchiveFilesDone(
682 const std::vector<int64_t>& offline_ids,
683 const DeletePageCallback& callback,
684 bool success) {
685 if (!success) {
686 InformDeletePageDone(callback, DeletePageResult::DEVICE_FAILURE);
687 return;
688 }
689
690 store_->RemoveOfflinePages(
691 offline_ids,
692 base::Bind(&OfflinePageModel::OnRemoveOfflinePagesDone,
693 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
694 }
695
696 void OfflinePageModel::OnRemoveOfflinePagesDone(
697 const std::vector<int64_t>& offline_ids,
698 const DeletePageCallback& callback,
699 bool success) {
700 // Delete the offline page from the in memory cache regardless of success in
701 // store.
702 base::Time now = base::Time::Now();
703 int64_t total_size = 0;
704 for (int64_t offline_id : offline_ids) {
705 auto iter = offline_pages_.find(offline_id);
706 if (iter == offline_pages_.end())
707 continue;
708 total_size += iter->second.file_size;
709 ClientId client_id = iter->second.client_id;
710 UMA_HISTOGRAM_CUSTOM_COUNTS(
711 AddHistogramSuffix(client_id, "OfflinePages.PageLifetime").c_str(),
712 (now - iter->second.creation_time).InMinutes(),
713 1,
714 base::TimeDelta::FromDays(365).InMinutes(),
715 100);
716 UMA_HISTOGRAM_CUSTOM_COUNTS(
717 AddHistogramSuffix(
718 client_id, "OfflinePages.DeletePage.TimeSinceLastOpen").c_str(),
719 (now - iter->second.last_access_time).InMinutes(),
720 1,
721 base::TimeDelta::FromDays(365).InMinutes(),
722 100);
723 UMA_HISTOGRAM_CUSTOM_COUNTS(
724 AddHistogramSuffix(
725 client_id, "OfflinePages.DeletePage.LastOpenToCreated").c_str(),
726 (iter->second.last_access_time - iter->second.creation_time).
727 InMinutes(),
728 1,
729 base::TimeDelta::FromDays(365).InMinutes(),
730 100);
731 UMA_HISTOGRAM_MEMORY_KB(
732 AddHistogramSuffix(
733 client_id, "OfflinePages.DeletePage.PageSize").c_str(),
734 iter->second.file_size / 1024);
735 UMA_HISTOGRAM_COUNTS(
736 AddHistogramSuffix(
737 client_id, "OfflinePages.DeletePage.AccessCount").c_str(),
738 iter->second.access_count);
739 FOR_EACH_OBSERVER(
740 Observer, observers_,
741 OfflinePageDeleted(iter->second.offline_id, iter->second.client_id));
742 offline_pages_.erase(iter);
743 }
744 if (offline_ids.size() > 1) {
745 UMA_HISTOGRAM_COUNTS("OfflinePages.BatchDelete.Count",
746 static_cast<int32_t>(offline_ids.size()));
747 UMA_HISTOGRAM_MEMORY_KB(
748 "OfflinePages.BatchDelete.TotalPageSize", total_size / 1024);
749 }
750 // Deleting multiple pages always succeeds when it gets to this point.
751 InformDeletePageDone(callback, (success || offline_ids.size() > 1)
752 ? DeletePageResult::SUCCESS
753 : DeletePageResult::STORE_FAILURE);
754 }
755
756 void OfflinePageModel::InformDeletePageDone(const DeletePageCallback& callback,
757 DeletePageResult result) {
758 UMA_HISTOGRAM_ENUMERATION(
759 "OfflinePages.DeletePageResult",
760 static_cast<int>(result),
761 static_cast<int>(DeletePageResult::RESULT_COUNT));
762 archive_manager_->GetStorageStats(
763 base::Bind(&ReportStorageHistogramsAfterDelete));
764 if (!callback.is_null())
765 callback.Run(result);
766 }
767
768 void OfflinePageModel::ScanForMissingArchiveFiles(
769 const std::set<base::FilePath>& archive_paths) {
770 std::vector<int64_t> ids_of_pages_missing_archive_file;
771 std::vector<std::pair<int64_t, ClientId>> offline_client_id_pairs;
772 for (const auto& id_page_pair : offline_pages_) {
773 if (archive_paths.count(id_page_pair.second.file_path) == 0UL) {
774 ids_of_pages_missing_archive_file.push_back(id_page_pair.first);
775 offline_client_id_pairs.push_back(
776 std::make_pair(id_page_pair.first, id_page_pair.second.client_id));
777 }
778 }
779
780 // No offline pages missing archive files, we can bail out.
781 if (ids_of_pages_missing_archive_file.empty())
782 return;
783
784 DeletePageCallback remove_pages_done_callback(
785 base::Bind(&OfflinePageModel::OnRemoveOfflinePagesMissingArchiveFileDone,
786 weak_ptr_factory_.GetWeakPtr(), offline_client_id_pairs));
787
788 store_->RemoveOfflinePages(
789 ids_of_pages_missing_archive_file,
790 base::Bind(&OfflinePageModel::OnRemoveOfflinePagesDone,
791 weak_ptr_factory_.GetWeakPtr(),
792 ids_of_pages_missing_archive_file,
793 remove_pages_done_callback));
794 }
795
796 void OfflinePageModel::OnRemoveOfflinePagesMissingArchiveFileDone(
797 const std::vector<std::pair<int64_t, ClientId>>& offline_client_id_pairs,
798 DeletePageResult /* result */) {
799 for (const auto& id_pair : offline_client_id_pairs) {
800 FOR_EACH_OBSERVER(Observer, observers_,
801 OfflinePageDeleted(id_pair.first, id_pair.second));
802 }
803 }
804
805 void OfflinePageModel::OnRemoveAllFilesDoneForClearAll(
806 const base::Closure& callback,
807 DeletePageResult result) {
808 store_->Reset(base::Bind(&OfflinePageModel::OnResetStoreDoneForClearAll,
809 weak_ptr_factory_.GetWeakPtr(),
810 callback));
811 }
812
813 void OfflinePageModel::OnResetStoreDoneForClearAll(
814 const base::Closure& callback, bool success) {
815 DCHECK(success);
816 if (!success) {
817 UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearAllStatus2",
818 STORE_RESET_FAILED,
819 CLEAR_ALL_STATUS_COUNT);
820 }
821
822 offline_pages_.clear();
823 store_->Load(base::Bind(&OfflinePageModel::OnReloadStoreDoneForClearAll,
824 weak_ptr_factory_.GetWeakPtr(),
825 callback));
826 }
827
828 void OfflinePageModel::OnReloadStoreDoneForClearAll(
829 const base::Closure& callback,
830 OfflinePageMetadataStore::LoadStatus load_status,
831 const std::vector<OfflinePageItem>& offline_pages) {
832 DCHECK_EQ(OfflinePageMetadataStore::LOAD_SUCCEEDED, load_status);
833 UMA_HISTOGRAM_ENUMERATION(
834 "OfflinePages.ClearAllStatus2",
835 load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED ?
836 CLEAR_ALL_SUCCEEDED : STORE_RELOAD_FAILED,
837 CLEAR_ALL_STATUS_COUNT);
838
839 CacheLoadedData(offline_pages);
840 callback.Run();
841 }
842
843 void OfflinePageModel::CacheLoadedData(
844 const std::vector<OfflinePageItem>& offline_pages) {
845 offline_pages_.clear();
846 for (const auto& offline_page : offline_pages)
847 offline_pages_[offline_page.offline_id] = offline_page;
848 }
849
850 int64_t OfflinePageModel::GenerateOfflineId() {
851 return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1;
852 }
853
854 void OfflinePageModel::RunWhenLoaded(const base::Closure& task) {
855 if (!is_loaded_) {
856 delayed_tasks_.push_back(task);
857 return;
858 }
859
860 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
861 }
862 19
863 } // namespace offline_pages 20 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698