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

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

Powered by Google App Engine
This is Rietveld 408576698