OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/offline_pages/offline_page_model_impl.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
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/rand_util.h" | |
16 #include "base/sequenced_task_runner.h" | |
17 #include "base/strings/string16.h" | |
18 #include "base/strings/string_number_conversions.h" | |
19 #include "base/threading/thread_task_runner_handle.h" | |
20 #include "base/time/clock.h" | |
21 #include "base/time/time.h" | |
22 #include "components/offline_pages/archive_manager.h" | |
23 #include "components/offline_pages/client_namespace_constants.h" | |
24 #include "components/offline_pages/client_policy_controller.h" | |
25 #include "components/offline_pages/offline_page_item.h" | |
26 #include "components/offline_pages/offline_page_model_query.h" | |
27 #include "components/offline_pages/offline_page_storage_manager.h" | |
28 #include "url/gurl.h" | |
29 | |
30 using ArchiverResult = offline_pages::OfflinePageArchiver::ArchiverResult; | |
31 using ClearStorageCallback = | |
32 offline_pages::OfflinePageStorageManager::ClearStorageCallback; | |
33 using ClearStorageResult = | |
34 offline_pages::OfflinePageStorageManager::ClearStorageResult; | |
35 | |
36 namespace offline_pages { | |
37 | |
38 namespace { | |
39 | |
40 // The delay used to schedule the first clear storage request for storage | |
41 // manager after the model is loaded. | |
42 const base::TimeDelta kStorageManagerStartingDelay = | |
43 base::TimeDelta::FromSeconds(20); | |
44 | |
45 int64_t GenerateOfflineId() { | |
46 return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1; | |
47 } | |
48 | |
49 // The maximum histogram size for the metrics that measure time between views of | |
50 // a given page. | |
51 const base::TimeDelta kMaxOpenedPageHistogramBucket = | |
52 base::TimeDelta::FromDays(90); | |
53 | |
54 SavePageResult ToSavePageResult(ArchiverResult archiver_result) { | |
55 SavePageResult result; | |
56 switch (archiver_result) { | |
57 case ArchiverResult::SUCCESSFULLY_CREATED: | |
58 result = SavePageResult::SUCCESS; | |
59 break; | |
60 case ArchiverResult::ERROR_DEVICE_FULL: | |
61 result = SavePageResult::DEVICE_FULL; | |
62 break; | |
63 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE: | |
64 result = SavePageResult::CONTENT_UNAVAILABLE; | |
65 break; | |
66 case ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED: | |
67 result = SavePageResult::ARCHIVE_CREATION_FAILED; | |
68 break; | |
69 case ArchiverResult::ERROR_CANCELED: | |
70 result = SavePageResult::CANCELLED; | |
71 break; | |
72 case ArchiverResult::ERROR_SECURITY_CERTIFICATE: | |
73 result = SavePageResult::SECURITY_CERTIFICATE_ERROR; | |
74 break; | |
75 default: | |
76 NOTREACHED(); | |
77 result = SavePageResult::CONTENT_UNAVAILABLE; | |
78 } | |
79 return result; | |
80 } | |
81 | |
82 std::string AddHistogramSuffix(const ClientId& client_id, | |
83 const char* histogram_name) { | |
84 if (client_id.name_space.empty()) { | |
85 NOTREACHED(); | |
86 return histogram_name; | |
87 } | |
88 std::string adjusted_histogram_name(histogram_name); | |
89 adjusted_histogram_name += "."; | |
90 adjusted_histogram_name += client_id.name_space; | |
91 return adjusted_histogram_name; | |
92 } | |
93 | |
94 void ReportStorageHistogramsAfterSave( | |
95 const ArchiveManager::StorageStats& storage_stats) { | |
96 const int kMB = 1024 * 1024; | |
97 int free_disk_space_mb = | |
98 static_cast<int>(storage_stats.free_disk_space / kMB); | |
99 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.SavePage.FreeSpaceMB", | |
100 free_disk_space_mb, 1, 500000, 50); | |
101 | |
102 int total_page_size_mb = | |
103 static_cast<int>(storage_stats.total_archives_size / kMB); | |
104 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb); | |
105 } | |
106 | |
107 void ReportStorageHistogramsAfterDelete( | |
108 const ArchiveManager::StorageStats& storage_stats) { | |
109 const int kMB = 1024 * 1024; | |
110 int free_disk_space_mb = | |
111 static_cast<int>(storage_stats.free_disk_space / kMB); | |
112 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DeletePage.FreeSpaceMB", | |
113 free_disk_space_mb, 1, 500000, 50); | |
114 | |
115 int total_page_size_mb = | |
116 static_cast<int>(storage_stats.total_archives_size / kMB); | |
117 UMA_HISTOGRAM_COUNTS_10000("OfflinePages.TotalPageSize", total_page_size_mb); | |
118 | |
119 if (storage_stats.free_disk_space > 0) { | |
120 int percentage_of_free = static_cast<int>( | |
121 1.0 * storage_stats.total_archives_size / | |
122 (storage_stats.total_archives_size + storage_stats.free_disk_space) * | |
123 100); | |
124 UMA_HISTOGRAM_PERCENTAGE( | |
125 "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace", | |
126 percentage_of_free); | |
127 } | |
128 } | |
129 | |
130 void ReportSavePageResultHistogramAfterSave(const ClientId& client_id, | |
131 SavePageResult result) { | |
132 // The histogram below is an expansion of the UMA_HISTOGRAM_ENUMERATION | |
133 // macro adapted to allow for a dynamically suffixed histogram name. | |
134 // Note: The factory creates and owns the histogram. | |
135 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( | |
136 AddHistogramSuffix(client_id, "OfflinePages.SavePageResult"), | |
137 1, | |
138 static_cast<int>(SavePageResult::RESULT_COUNT), | |
139 static_cast<int>(SavePageResult::RESULT_COUNT) + 1, | |
140 base::HistogramBase::kUmaTargetedHistogramFlag); | |
141 histogram->Add(static_cast<int>(result)); | |
142 } | |
143 | |
144 // Goes through the list of offline pages, compiling the following two metrics: | |
145 // - a count of the pages with the same URL | |
146 // - The difference between the |created_before| time and the creation time of | |
147 // the page with the closest creation time before |created_before|. | |
148 // Returns true if there was a page that was saved before |created_before| with | |
149 // a matching URL. | |
150 bool GetMatchingURLCountAndMostRecentCreationTime( | |
151 const std::map<int64_t, OfflinePageItem>& offline_pages, | |
152 std::string name_space, | |
153 const GURL& url, | |
154 base::Time created_before, | |
155 int* matching_url_count, | |
156 base::TimeDelta* most_recent_creation_time) { | |
157 int count = 0; | |
158 | |
159 // Create a time that is very old, so that any valid time will be newer than | |
160 // it. | |
161 base::Time latest_time; | |
162 bool matching_page = false; | |
163 | |
164 for (auto& id_page_pair : offline_pages) { | |
165 if (id_page_pair.second.client_id.name_space == name_space && | |
166 url == id_page_pair.second.url) { | |
167 count++; | |
168 base::Time page_creation_time = id_page_pair.second.creation_time; | |
169 if (page_creation_time < created_before && | |
170 page_creation_time > latest_time) { | |
171 latest_time = page_creation_time; | |
172 matching_page = true; | |
173 } | |
174 } | |
175 } | |
176 | |
177 if (matching_url_count != nullptr) | |
178 *matching_url_count = count; | |
179 if (most_recent_creation_time != nullptr && latest_time != base::Time()) | |
180 *most_recent_creation_time = created_before - latest_time; | |
181 | |
182 return matching_page; | |
183 } | |
184 | |
185 void ReportPageHistogramAfterSave( | |
186 const std::map<int64_t, OfflinePageItem>& offline_pages, | |
187 const OfflinePageItem& offline_page, | |
188 const base::Time& save_time) { | |
189 // The histogram below is an expansion of the UMA_HISTOGRAM_TIMES | |
190 // macro adapted to allow for a dynamically suffixed histogram name. | |
191 // Note: The factory creates and owns the histogram. | |
192 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( | |
193 AddHistogramSuffix(offline_page.client_id, "OfflinePages.SavePageTime"), | |
194 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10), | |
195 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
196 histogram->AddTime(save_time - offline_page.creation_time); | |
197 | |
198 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
199 // macro adapted to allow for a dynamically suffixed histogram name. | |
200 // Note: The factory creates and owns the histogram. | |
201 // Reported as Kb between 1Kb and 10Mb. | |
202 histogram = base::Histogram::FactoryGet( | |
203 AddHistogramSuffix(offline_page.client_id, "OfflinePages.PageSize"), | |
204 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
205 histogram->Add(offline_page.file_size / 1024); | |
206 | |
207 if (offline_page.client_id.name_space == kDownloadNamespace) { | |
208 int matching_url_count; | |
209 base::TimeDelta time_since_most_recent_duplicate; | |
210 if (GetMatchingURLCountAndMostRecentCreationTime( | |
211 offline_pages, offline_page.client_id.name_space, offline_page.url, | |
212 offline_page.creation_time, &matching_url_count, | |
213 &time_since_most_recent_duplicate)) { | |
214 // Using CUSTOM_COUNTS instead of time-oriented histogram to record | |
215 // samples in seconds rather than milliseconds. | |
216 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
217 "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved", | |
218 time_since_most_recent_duplicate.InSeconds(), | |
219 base::TimeDelta::FromSeconds(1).InSeconds(), | |
220 base::TimeDelta::FromDays(7).InSeconds(), 50); | |
221 } | |
222 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DownloadSavedPageDuplicateCount", | |
223 matching_url_count, 1, 20, 10); | |
224 } | |
225 } | |
226 | |
227 void ReportPageHistogramsAfterDelete( | |
228 const std::map<int64_t, OfflinePageItem>& offline_pages, | |
229 const std::vector<OfflinePageItem>& deleted_pages, | |
230 const base::Time& delete_time) { | |
231 const int max_minutes = base::TimeDelta::FromDays(365).InMinutes(); | |
232 int64_t total_size = 0; | |
233 | |
234 for (const auto& page : deleted_pages) { | |
235 total_size += page.file_size; | |
236 ClientId client_id = page.client_id; | |
237 | |
238 if (client_id.name_space == kDownloadNamespace) { | |
239 int remaining_pages_with_url; | |
240 GetMatchingURLCountAndMostRecentCreationTime( | |
241 offline_pages, page.client_id.name_space, page.url, base::Time::Max(), | |
242 &remaining_pages_with_url, nullptr); | |
243 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
244 "OfflinePages.DownloadDeletedPageDuplicateCount", | |
245 remaining_pages_with_url, 1, 20, 10); | |
246 } | |
247 | |
248 // The histograms below are an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
249 // macro adapted to allow for a dynamically suffixed histogram name. | |
250 // Note: The factory creates and owns the histogram. | |
251 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
252 AddHistogramSuffix(client_id, "OfflinePages.PageLifetime"), | |
253 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
254 histogram->Add((delete_time - page.creation_time).InMinutes()); | |
255 | |
256 histogram = base::Histogram::FactoryGet( | |
257 AddHistogramSuffix( | |
258 client_id, "OfflinePages.DeletePage.TimeSinceLastOpen"), | |
259 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
260 histogram->Add((delete_time - page.last_access_time).InMinutes()); | |
261 | |
262 histogram = base::Histogram::FactoryGet( | |
263 AddHistogramSuffix( | |
264 client_id, "OfflinePages.DeletePage.LastOpenToCreated"), | |
265 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
266 histogram->Add((page.last_access_time - page.creation_time).InMinutes()); | |
267 | |
268 // Reported as Kb between 1Kb and 10Mb. | |
269 histogram = base::Histogram::FactoryGet( | |
270 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.PageSize"), | |
271 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
272 histogram->Add(page.file_size / 1024); | |
273 | |
274 histogram = base::Histogram::FactoryGet( | |
275 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.AccessCount"), | |
276 1, 1000000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
277 histogram->Add(page.access_count); | |
278 } | |
279 | |
280 if (deleted_pages.size() > 1) { | |
281 UMA_HISTOGRAM_COUNTS("OfflinePages.BatchDelete.Count", | |
282 static_cast<int32_t>(deleted_pages.size())); | |
283 UMA_HISTOGRAM_MEMORY_KB( | |
284 "OfflinePages.BatchDelete.TotalPageSize", total_size / 1024); | |
285 } | |
286 } | |
287 | |
288 void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item, | |
289 const base::Time& access_time) { | |
290 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
291 // macro adapted to allow for a dynamically suffixed histogram name. | |
292 // Note: The factory creates and owns the histogram. | |
293 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
294 AddHistogramSuffix( | |
295 offline_page_item.client_id, | |
296 offline_page_item.access_count == 0 ? | |
297 "OfflinePages.FirstOpenSinceCreated" : | |
298 "OfflinePages.OpenSinceLastOpen"), | |
299 1, kMaxOpenedPageHistogramBucket.InMinutes(), 50, | |
300 base::HistogramBase::kUmaTargetedHistogramFlag); | |
301 histogram->Add( | |
302 (access_time - offline_page_item.last_access_time).InMinutes()); | |
303 } | |
304 | |
305 } // namespace | |
306 | |
307 // protected | |
308 OfflinePageModelImpl::OfflinePageModelImpl() | |
309 : OfflinePageModel(), is_loaded_(false), weak_ptr_factory_(this) {} | |
310 | |
311 OfflinePageModelImpl::OfflinePageModelImpl( | |
312 std::unique_ptr<OfflinePageMetadataStore> store, | |
313 const base::FilePath& archives_dir, | |
314 const scoped_refptr<base::SequencedTaskRunner>& task_runner) | |
315 : store_(std::move(store)), | |
316 archives_dir_(archives_dir), | |
317 is_loaded_(false), | |
318 policy_controller_(new ClientPolicyController()), | |
319 archive_manager_(new ArchiveManager(archives_dir, task_runner)), | |
320 testing_clock_(nullptr), | |
321 weak_ptr_factory_(this) { | |
322 archive_manager_->EnsureArchivesDirCreated( | |
323 base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone, | |
324 weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now())); | |
325 } | |
326 | |
327 OfflinePageModelImpl::~OfflinePageModelImpl() {} | |
328 | |
329 void OfflinePageModelImpl::AddObserver(Observer* observer) { | |
330 observers_.AddObserver(observer); | |
331 } | |
332 | |
333 void OfflinePageModelImpl::RemoveObserver(Observer* observer) { | |
334 observers_.RemoveObserver(observer); | |
335 } | |
336 | |
337 void OfflinePageModelImpl::SavePage( | |
338 const SavePageParams& save_page_params, | |
339 std::unique_ptr<OfflinePageArchiver> archiver, | |
340 const SavePageCallback& callback) { | |
341 DCHECK(is_loaded_); | |
342 | |
343 // Skip saving the page that is not intended to be saved, like local file | |
344 // page. | |
345 if (!OfflinePageModel::CanSaveURL(save_page_params.url)) { | |
346 InformSavePageDone(callback, SavePageResult::SKIPPED, | |
347 save_page_params.client_id, kInvalidOfflineId); | |
348 return; | |
349 } | |
350 | |
351 // The web contents is not available if archiver is not created and passed. | |
352 if (!archiver.get()) { | |
353 InformSavePageDone(callback, SavePageResult::CONTENT_UNAVAILABLE, | |
354 save_page_params.client_id, kInvalidOfflineId); | |
355 return; | |
356 } | |
357 | |
358 // If we already have an offline id, use it. If not, generate one. | |
359 int64_t offline_id = save_page_params.proposed_offline_id; | |
360 if (offline_id == kInvalidOfflineId) | |
361 offline_id = GenerateOfflineId(); | |
362 | |
363 archiver->CreateArchive( | |
364 archives_dir_, offline_id, | |
365 base::Bind(&OfflinePageModelImpl::OnCreateArchiveDone, | |
366 weak_ptr_factory_.GetWeakPtr(), save_page_params, offline_id, | |
367 GetCurrentTime(), callback)); | |
368 pending_archivers_.push_back(std::move(archiver)); | |
369 } | |
370 | |
371 void OfflinePageModelImpl::MarkPageAccessed(int64_t offline_id) { | |
372 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::MarkPageAccessedWhenLoadDone, | |
373 weak_ptr_factory_.GetWeakPtr(), offline_id)); | |
374 } | |
375 | |
376 void OfflinePageModelImpl::MarkPageAccessedWhenLoadDone(int64_t offline_id) { | |
377 DCHECK(is_loaded_); | |
378 | |
379 auto iter = offline_pages_.find(offline_id); | |
380 if (iter == offline_pages_.end() || iter->second.IsExpired()) | |
381 return; | |
382 | |
383 // Make a copy of the cached item and update it. The cached item should only | |
384 // be updated upon the successful store operation. | |
385 OfflinePageItem offline_page_item = iter->second; | |
386 | |
387 ReportPageHistogramsAfterAccess(offline_page_item, GetCurrentTime()); | |
388 | |
389 offline_page_item.last_access_time = GetCurrentTime(); | |
390 offline_page_item.access_count++; | |
391 | |
392 std::vector<OfflinePageItem> items = { offline_page_item }; | |
393 store_->UpdateOfflinePages( | |
394 items, base::Bind(&OfflinePageModelImpl::OnMarkPageAccesseDone, | |
395 weak_ptr_factory_.GetWeakPtr(), offline_page_item)); | |
396 } | |
397 | |
398 void OfflinePageModelImpl::DeletePagesByOfflineId( | |
399 const std::vector<int64_t>& offline_ids, | |
400 const DeletePageCallback& callback) { | |
401 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::DoDeletePagesByOfflineId, | |
402 weak_ptr_factory_.GetWeakPtr(), offline_ids, | |
403 callback)); | |
404 } | |
405 | |
406 void OfflinePageModelImpl::DoDeletePagesByOfflineId( | |
407 const std::vector<int64_t>& offline_ids, | |
408 const DeletePageCallback& callback) { | |
409 DCHECK(is_loaded_); | |
410 | |
411 std::vector<base::FilePath> paths_to_delete; | |
412 for (const auto& offline_id : offline_ids) { | |
413 auto iter = offline_pages_.find(offline_id); | |
414 if (iter != offline_pages_.end() && !iter->second.IsExpired()) { | |
415 paths_to_delete.push_back(iter->second.file_path); | |
416 } | |
417 } | |
418 | |
419 // If there're no pages to delete, return early. | |
420 if (paths_to_delete.empty()) { | |
421 InformDeletePageDone(callback, DeletePageResult::SUCCESS); | |
422 return; | |
423 } | |
424 | |
425 archive_manager_->DeleteMultipleArchives( | |
426 paths_to_delete, | |
427 base::Bind(&OfflinePageModelImpl::OnDeleteArchiveFilesDone, | |
428 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback)); | |
429 } | |
430 | |
431 void OfflinePageModelImpl::DeletePagesByClientIds( | |
432 const std::vector<ClientId>& client_ids, | |
433 const DeletePageCallback& callback) { | |
434 OfflinePageModelQueryBuilder builder; | |
435 builder | |
436 .SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
437 client_ids) | |
438 .AllowExpiredPages(true); | |
439 auto delete_pages = base::Bind(&OfflinePageModelImpl::DeletePages, | |
440 weak_ptr_factory_.GetWeakPtr(), callback); | |
441 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
442 weak_ptr_factory_.GetWeakPtr(), | |
443 base::Passed(builder.Build(GetPolicyController())), | |
444 delete_pages)); | |
445 } | |
446 | |
447 void OfflinePageModelImpl::DeletePages( | |
448 const DeletePageCallback& callback, | |
449 const MultipleOfflinePageItemResult& pages) { | |
450 DCHECK(is_loaded_); | |
451 | |
452 std::vector<int64_t> offline_ids; | |
453 for (auto& page : pages) | |
454 offline_ids.emplace_back(page.offline_id); | |
455 | |
456 DoDeletePagesByOfflineId(offline_ids, callback); | |
457 } | |
458 | |
459 void OfflinePageModelImpl::GetPagesByClientIds( | |
460 const std::vector<ClientId>& client_ids, | |
461 const MultipleOfflinePageItemCallback& callback) { | |
462 OfflinePageModelQueryBuilder builder; | |
463 builder.SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
464 client_ids); | |
465 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
466 weak_ptr_factory_.GetWeakPtr(), | |
467 base::Passed(builder.Build(GetPolicyController())), | |
468 callback)); | |
469 } | |
470 | |
471 void OfflinePageModelImpl::DeleteCachedPagesByURLPredicate( | |
472 const UrlPredicate& predicate, | |
473 const DeletePageCallback& callback) { | |
474 RunWhenLoaded( | |
475 base::Bind(&OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate, | |
476 weak_ptr_factory_.GetWeakPtr(), predicate, callback)); | |
477 } | |
478 | |
479 void OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate( | |
480 const UrlPredicate& predicate, | |
481 const DeletePageCallback& callback) { | |
482 DCHECK(is_loaded_); | |
483 | |
484 std::vector<int64_t> offline_ids; | |
485 for (const auto& id_page_pair : offline_pages_) { | |
486 if (IsRemovedOnCacheReset(id_page_pair.second) && | |
487 predicate.Run(id_page_pair.second.url)) { | |
488 offline_ids.push_back(id_page_pair.first); | |
489 } | |
490 } | |
491 DoDeletePagesByOfflineId(offline_ids, callback); | |
492 } | |
493 | |
494 void OfflinePageModelImpl::CheckPagesExistOffline( | |
495 const std::set<GURL>& urls, | |
496 const CheckPagesExistOfflineCallback& callback) { | |
497 OfflinePageModelQueryBuilder builder; | |
498 builder | |
499 .SetUrls(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
500 std::vector<GURL>(urls.begin(), urls.end())) | |
501 .RequireRestrictedToOriginalTab( | |
502 OfflinePageModelQueryBuilder::Requirement::EXCLUDE_MATCHING); | |
503 auto pages_to_urls = base::Bind( | |
504 [](const CheckPagesExistOfflineCallback& callback, | |
505 const MultipleOfflinePageItemResult& pages) { | |
506 CheckPagesExistOfflineResult result; | |
507 for (auto& page : pages) | |
508 result.insert(page.url); | |
509 callback.Run(result); | |
510 }, | |
511 callback); | |
512 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
513 weak_ptr_factory_.GetWeakPtr(), | |
514 base::Passed(builder.Build(GetPolicyController())), | |
515 pages_to_urls)); | |
516 } | |
517 | |
518 void OfflinePageModelImpl::GetPagesMatchingQuery( | |
519 std::unique_ptr<OfflinePageModelQuery> query, | |
520 const MultipleOfflinePageItemCallback& callback) { | |
521 DCHECK(query); | |
522 | |
523 MultipleOfflinePageItemResult offline_pages_result; | |
524 | |
525 for (const auto& id_page_pair : offline_pages_) { | |
526 if (query->Matches(id_page_pair.second)) | |
527 offline_pages_result.emplace_back(id_page_pair.second); | |
528 } | |
529 | |
530 callback.Run(offline_pages_result); | |
531 } | |
532 | |
533 void OfflinePageModelImpl::GetAllPages( | |
534 const MultipleOfflinePageItemCallback& callback) { | |
535 OfflinePageModelQueryBuilder builder; | |
536 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
537 weak_ptr_factory_.GetWeakPtr(), | |
538 base::Passed(builder.Build(GetPolicyController())), | |
539 callback)); | |
540 } | |
541 | |
542 void OfflinePageModelImpl::GetAllPagesWithExpired( | |
543 const MultipleOfflinePageItemCallback& callback) { | |
544 OfflinePageModelQueryBuilder builder; | |
545 builder.AllowExpiredPages(true); | |
546 | |
547 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
548 weak_ptr_factory_.GetWeakPtr(), | |
549 base::Passed(builder.Build(GetPolicyController())), | |
550 callback)); | |
551 } | |
552 | |
553 void OfflinePageModelImpl::GetOfflineIdsForClientId( | |
554 const ClientId& client_id, | |
555 const MultipleOfflineIdCallback& callback) { | |
556 RunWhenLoaded( | |
557 base::Bind(&OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone, | |
558 weak_ptr_factory_.GetWeakPtr(), client_id, callback)); | |
559 } | |
560 | |
561 void OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone( | |
562 const ClientId& client_id, | |
563 const MultipleOfflineIdCallback& callback) const { | |
564 callback.Run(MaybeGetOfflineIdsForClientId(client_id)); | |
565 } | |
566 | |
567 const std::vector<int64_t> OfflinePageModelImpl::MaybeGetOfflineIdsForClientId( | |
568 const ClientId& client_id) const { | |
569 DCHECK(is_loaded_); | |
570 std::vector<int64_t> results; | |
571 | |
572 // We want only all pages, including those marked for deletion. | |
573 // TODO(fgorski): actually use an index rather than linear scan. | |
574 for (const auto& id_page_pair : offline_pages_) { | |
575 if (id_page_pair.second.client_id == client_id && | |
576 !id_page_pair.second.IsExpired()) { | |
577 results.push_back(id_page_pair.second.offline_id); | |
578 } | |
579 } | |
580 return results; | |
581 } | |
582 | |
583 void OfflinePageModelImpl::GetPageByOfflineId( | |
584 int64_t offline_id, | |
585 const SingleOfflinePageItemCallback& callback) { | |
586 std::vector<int64_t> query_ids; | |
587 query_ids.emplace_back(offline_id); | |
588 | |
589 OfflinePageModelQueryBuilder builder; | |
590 builder.SetOfflinePageIds( | |
591 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, query_ids); | |
592 | |
593 auto multiple_callback = base::Bind( | |
594 [](const SingleOfflinePageItemCallback& callback, | |
595 const MultipleOfflinePageItemResult& result) { | |
596 DCHECK_LE(result.size(), 1U); | |
597 if (result.empty()) { | |
598 callback.Run(nullptr); | |
599 } else { | |
600 callback.Run(&result[0]); | |
601 } | |
602 }, | |
603 callback); | |
604 | |
605 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetPagesMatchingQuery, | |
606 weak_ptr_factory_.GetWeakPtr(), | |
607 base::Passed(builder.Build(GetPolicyController())), | |
608 multiple_callback)); | |
609 } | |
610 | |
611 void OfflinePageModelImpl::GetPagesByOnlineURL( | |
612 const GURL& online_url, | |
613 const MultipleOfflinePageItemCallback& callback) { | |
614 RunWhenLoaded( | |
615 base::Bind(&OfflinePageModelImpl::GetPagesByOnlineURLWhenLoadDone, | |
616 weak_ptr_factory_.GetWeakPtr(), online_url, callback)); | |
617 } | |
618 | |
619 void OfflinePageModelImpl::GetPagesByOnlineURLWhenLoadDone( | |
620 const GURL& online_url, | |
621 const MultipleOfflinePageItemCallback& callback) const { | |
622 std::vector<OfflinePageItem> result; | |
623 | |
624 GURL::Replacements remove_params; | |
625 remove_params.ClearRef(); | |
626 | |
627 GURL online_url_without_fragment = | |
628 online_url.ReplaceComponents(remove_params); | |
629 | |
630 for (const auto& id_page_pair : offline_pages_) { | |
631 if (id_page_pair.second.IsExpired()) | |
632 continue; | |
633 if (online_url == id_page_pair.second.url) { | |
634 result.push_back(id_page_pair.second); | |
635 continue; | |
636 } | |
637 // If the full URL does not match, try with the fragment identifier | |
638 // stripped. | |
639 if (online_url_without_fragment == | |
640 id_page_pair.second.url.ReplaceComponents(remove_params)) { | |
641 result.push_back(id_page_pair.second); | |
642 } | |
643 } | |
644 | |
645 callback.Run(result); | |
646 } | |
647 | |
648 void OfflinePageModelImpl::CheckMetadataConsistency() { | |
649 DCHECK(is_loaded_); | |
650 archive_manager_->GetAllArchives( | |
651 base::Bind(&OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths, | |
652 weak_ptr_factory_.GetWeakPtr())); | |
653 } | |
654 | |
655 void OfflinePageModelImpl::ExpirePages( | |
656 const std::vector<int64_t>& offline_ids, | |
657 const base::Time& expiration_time, | |
658 const base::Callback<void(bool)>& callback) { | |
659 std::vector<base::FilePath> paths_to_delete; | |
660 std::vector<OfflinePageItem> items_to_update; | |
661 for (int64_t offline_id : offline_ids) { | |
662 auto iter = offline_pages_.find(offline_id); | |
663 if (iter == offline_pages_.end()) | |
664 continue; | |
665 | |
666 OfflinePageItem offline_page = iter->second; | |
667 paths_to_delete.push_back(offline_page.file_path); | |
668 offline_page.expiration_time = expiration_time; | |
669 | |
670 items_to_update.push_back(offline_page); | |
671 } | |
672 | |
673 store_->UpdateOfflinePages( | |
674 items_to_update, | |
675 base::Bind(&OfflinePageModelImpl::OnExpirePageDone, | |
676 weak_ptr_factory_.GetWeakPtr(), expiration_time)); | |
677 | |
678 if (paths_to_delete.empty()) { | |
679 callback.Run(true); | |
680 return; | |
681 } | |
682 archive_manager_->DeleteMultipleArchives(paths_to_delete, callback); | |
683 } | |
684 | |
685 void OfflinePageModelImpl::OnExpirePageDone( | |
686 const base::Time& expiration_time, | |
687 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
688 UMA_HISTOGRAM_BOOLEAN("OfflinePages.ExpirePage.StoreUpdateResult", | |
689 result->updated_items.size() > 0); | |
690 for (const auto& expired_page : result->updated_items) { | |
691 const auto& iter = offline_pages_.find(expired_page.offline_id); | |
692 if (iter == offline_pages_.end()) | |
693 continue; | |
694 | |
695 iter->second.expiration_time = expiration_time; | |
696 ClientId client_id = iter->second.client_id; | |
697 offline_event_logger_.RecordPageExpired( | |
698 std::to_string(expired_page.offline_id)); | |
699 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
700 AddHistogramSuffix(client_id, "OfflinePages.ExpirePage.PageLifetime"), | |
701 1, base::TimeDelta::FromDays(30).InMinutes(), 50, | |
702 base::HistogramBase::kUmaTargetedHistogramFlag); | |
703 histogram->Add((expiration_time - iter->second.creation_time).InMinutes()); | |
704 histogram = base::Histogram::FactoryGet( | |
705 AddHistogramSuffix(client_id, | |
706 "OfflinePages.ExpirePage.TimeSinceLastAccess"), | |
707 1, base::TimeDelta::FromDays(30).InMinutes(), 50, | |
708 base::HistogramBase::kUmaTargetedHistogramFlag); | |
709 histogram->Add( | |
710 (expiration_time - iter->second.last_access_time).InMinutes()); | |
711 } | |
712 } | |
713 | |
714 ClientPolicyController* OfflinePageModelImpl::GetPolicyController() { | |
715 return policy_controller_.get(); | |
716 } | |
717 | |
718 OfflinePageMetadataStore* OfflinePageModelImpl::GetStoreForTesting() { | |
719 return store_.get(); | |
720 } | |
721 | |
722 OfflinePageStorageManager* OfflinePageModelImpl::GetStorageManager() { | |
723 return storage_manager_.get(); | |
724 } | |
725 | |
726 bool OfflinePageModelImpl::is_loaded() const { | |
727 return is_loaded_; | |
728 } | |
729 | |
730 OfflineEventLogger* OfflinePageModelImpl::GetLogger() { | |
731 return &offline_event_logger_; | |
732 } | |
733 | |
734 void OfflinePageModelImpl::OnCreateArchiveDone( | |
735 const SavePageParams& save_page_params, | |
736 int64_t offline_id, | |
737 const base::Time& start_time, | |
738 const SavePageCallback& callback, | |
739 OfflinePageArchiver* archiver, | |
740 ArchiverResult archiver_result, | |
741 const GURL& url, | |
742 const base::FilePath& file_path, | |
743 const base::string16& title, | |
744 int64_t file_size) { | |
745 if (save_page_params.url != url) { | |
746 DVLOG(1) << "Saved URL does not match requested URL."; | |
747 // TODO(fgorski): We have created an archive for a wrong URL. It should be | |
748 // deleted from here, once archiver has the right functionality. | |
749 InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED, | |
750 save_page_params.client_id, offline_id); | |
751 DeletePendingArchiver(archiver); | |
752 return; | |
753 } | |
754 | |
755 if (archiver_result != ArchiverResult::SUCCESSFULLY_CREATED) { | |
756 SavePageResult result = ToSavePageResult(archiver_result); | |
757 InformSavePageDone( | |
758 callback, result, save_page_params.client_id, offline_id); | |
759 DeletePendingArchiver(archiver); | |
760 return; | |
761 } | |
762 OfflinePageItem offline_page_item(url, offline_id, save_page_params.client_id, | |
763 file_path, file_size, start_time); | |
764 offline_page_item.title = title; | |
765 offline_page_item.original_url = save_page_params.original_url; | |
766 store_->AddOfflinePage(offline_page_item, | |
767 base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone, | |
768 weak_ptr_factory_.GetWeakPtr(), archiver, | |
769 callback, offline_page_item)); | |
770 } | |
771 | |
772 void OfflinePageModelImpl::OnAddOfflinePageDone( | |
773 OfflinePageArchiver* archiver, | |
774 const SavePageCallback& callback, | |
775 const OfflinePageItem& offline_page, | |
776 ItemActionStatus status) { | |
777 SavePageResult result; | |
778 if (status == ItemActionStatus::SUCCESS) { | |
779 offline_pages_[offline_page.offline_id] = offline_page; | |
780 result = SavePageResult::SUCCESS; | |
781 ReportPageHistogramAfterSave(offline_pages_, offline_page, | |
782 GetCurrentTime()); | |
783 offline_event_logger_.RecordPageSaved( | |
784 offline_page.client_id.name_space, offline_page.url.spec(), | |
785 std::to_string(offline_page.offline_id)); | |
786 } else if (status == ItemActionStatus::ALREADY_EXISTS) { | |
787 result = SavePageResult::ALREADY_EXISTS; | |
788 } else { | |
789 result = SavePageResult::STORE_FAILURE; | |
790 } | |
791 InformSavePageDone(callback, result, offline_page.client_id, | |
792 offline_page.offline_id); | |
793 if (result == SavePageResult::SUCCESS) { | |
794 DeleteExistingPagesWithSameURL(offline_page); | |
795 } else { | |
796 PostClearStorageIfNeededTask(); | |
797 } | |
798 | |
799 DeletePendingArchiver(archiver); | |
800 for (Observer& observer : observers_) | |
801 observer.OfflinePageModelChanged(this); | |
802 } | |
803 | |
804 void OfflinePageModelImpl::OnMarkPageAccesseDone( | |
805 const OfflinePageItem& offline_page_item, | |
806 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
807 // Update the item in the cache only upon success. | |
808 if (result->updated_items.size() > 0) | |
809 offline_pages_[offline_page_item.offline_id] = offline_page_item; | |
810 | |
811 // No need to fire OfflinePageModelChanged event since updating access info | |
812 // should not have any impact to the UI. | |
813 } | |
814 | |
815 void OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone( | |
816 const base::TimeTicks& start_time) { | |
817 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime", | |
818 base::TimeTicks::Now() - start_time); | |
819 | |
820 store_->GetOfflinePages(base::Bind(&OfflinePageModelImpl::OnLoadDone, | |
821 weak_ptr_factory_.GetWeakPtr(), | |
822 start_time)); | |
823 } | |
824 | |
825 void OfflinePageModelImpl::OnLoadDone( | |
826 const base::TimeTicks& start_time, | |
827 OfflinePageMetadataStore::LoadStatus load_status, | |
828 const std::vector<OfflinePageItem>& offline_pages) { | |
829 DCHECK(!is_loaded_); | |
830 is_loaded_ = true; | |
831 | |
832 // TODO(jianli): rebuild the store upon failure. | |
833 | |
834 if (load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED) | |
835 CacheLoadedData(offline_pages); | |
836 | |
837 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ConstructionToLoadedEventTime", | |
838 base::TimeTicks::Now() - start_time); | |
839 | |
840 // Create Storage Manager. | |
841 storage_manager_.reset(new OfflinePageStorageManager( | |
842 this, GetPolicyController(), archive_manager_.get())); | |
843 | |
844 // Run all the delayed tasks. | |
845 for (const auto& delayed_task : delayed_tasks_) | |
846 delayed_task.Run(); | |
847 delayed_tasks_.clear(); | |
848 | |
849 for (Observer& observer : observers_) | |
850 observer.OfflinePageModelLoaded(this); | |
851 | |
852 CheckMetadataConsistency(); | |
853 | |
854 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
855 FROM_HERE, base::Bind(&OfflinePageModelImpl::ClearStorageIfNeeded, | |
856 weak_ptr_factory_.GetWeakPtr(), | |
857 base::Bind(&OfflinePageModelImpl::OnStorageCleared, | |
858 weak_ptr_factory_.GetWeakPtr())), | |
859 kStorageManagerStartingDelay); | |
860 } | |
861 | |
862 void OfflinePageModelImpl::InformSavePageDone(const SavePageCallback& callback, | |
863 SavePageResult result, | |
864 const ClientId& client_id, | |
865 int64_t offline_id) { | |
866 ReportSavePageResultHistogramAfterSave(client_id, result); | |
867 archive_manager_->GetStorageStats( | |
868 base::Bind(&ReportStorageHistogramsAfterSave)); | |
869 callback.Run(result, offline_id); | |
870 } | |
871 | |
872 void OfflinePageModelImpl::DeleteExistingPagesWithSameURL( | |
873 const OfflinePageItem& offline_page) { | |
874 // Remove existing pages generated by the same policy and with same url. | |
875 size_t pages_allowed = | |
876 policy_controller_->GetPolicy(offline_page.client_id.name_space) | |
877 .pages_allowed_per_url; | |
878 if (pages_allowed == kUnlimitedPages) | |
879 return; | |
880 GetPagesByOnlineURL( | |
881 offline_page.url, | |
882 base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL, | |
883 weak_ptr_factory_.GetWeakPtr(), offline_page, pages_allowed)); | |
884 } | |
885 | |
886 void OfflinePageModelImpl::OnPagesFoundWithSameURL( | |
887 const OfflinePageItem& offline_page, | |
888 size_t pages_allowed, | |
889 const MultipleOfflinePageItemResult& items) { | |
890 std::vector<OfflinePageItem> pages_to_delete; | |
891 for (const auto& item : items) { | |
892 if (item.offline_id != offline_page.offline_id && | |
893 item.client_id.name_space == offline_page.client_id.name_space) { | |
894 pages_to_delete.push_back(item); | |
895 } | |
896 } | |
897 // Only keep |pages_allowed|-1 of most fresh pages and delete others, by | |
898 // sorting pages with the oldest ones first and resize the vector. | |
899 if (pages_to_delete.size() >= pages_allowed) { | |
900 sort(pages_to_delete.begin(), pages_to_delete.end(), | |
901 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool { | |
902 return a.last_access_time < b.last_access_time; | |
903 }); | |
904 pages_to_delete.resize(pages_to_delete.size() - pages_allowed + 1); | |
905 } | |
906 std::vector<int64_t> page_ids_to_delete; | |
907 for (const auto& item : pages_to_delete) | |
908 page_ids_to_delete.push_back(item.offline_id); | |
909 DeletePagesByOfflineId( | |
910 page_ids_to_delete, | |
911 base::Bind(&OfflinePageModelImpl::OnDeleteOldPagesWithSameURL, | |
912 weak_ptr_factory_.GetWeakPtr())); | |
913 } | |
914 | |
915 void OfflinePageModelImpl::OnDeleteOldPagesWithSameURL( | |
916 DeletePageResult result) { | |
917 // TODO(romax) Add UMAs for failure cases. | |
918 PostClearStorageIfNeededTask(); | |
919 } | |
920 | |
921 void OfflinePageModelImpl::DeletePendingArchiver( | |
922 OfflinePageArchiver* archiver) { | |
923 pending_archivers_.erase(std::find(pending_archivers_.begin(), | |
924 pending_archivers_.end(), archiver)); | |
925 } | |
926 | |
927 void OfflinePageModelImpl::OnDeleteArchiveFilesDone( | |
928 const std::vector<int64_t>& offline_ids, | |
929 const DeletePageCallback& callback, | |
930 bool success) { | |
931 if (!success) { | |
932 InformDeletePageDone(callback, DeletePageResult::DEVICE_FAILURE); | |
933 return; | |
934 } | |
935 | |
936 store_->RemoveOfflinePages( | |
937 offline_ids, base::Bind(&OfflinePageModelImpl::OnRemoveOfflinePagesDone, | |
938 weak_ptr_factory_.GetWeakPtr(), callback)); | |
939 } | |
940 | |
941 void OfflinePageModelImpl::OnRemoveOfflinePagesDone( | |
942 const DeletePageCallback& callback, | |
943 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
944 ReportPageHistogramsAfterDelete(offline_pages_, result->updated_items, | |
945 GetCurrentTime()); | |
946 | |
947 // This part of the loop is explicitly broken out, as it should be gone in | |
948 // fully asynchronous code. | |
949 for (const auto& page : result->updated_items) { | |
950 int64_t offline_id = page.offline_id; | |
951 offline_event_logger_.RecordPageDeleted(std::to_string(offline_id)); | |
952 auto iter = offline_pages_.find(offline_id); | |
953 if (iter == offline_pages_.end()) | |
954 continue; | |
955 offline_pages_.erase(iter); | |
956 } | |
957 | |
958 for (const auto& page : result->updated_items) { | |
959 for (Observer& observer : observers_) | |
960 observer.OfflinePageDeleted(page.offline_id, page.client_id); | |
961 } | |
962 | |
963 // TODO(fgorski): React the FAILED_INITIALIZATION, FAILED_RESET here. | |
964 // TODO(fgorski): We need a better callback interface for the Remove action on | |
965 // the this class. Currently removing an item that does not exist is | |
966 // considered a success, but not called out as such to the caller. | |
967 DeletePageResult delete_result; | |
968 if (result->store_state == StoreState::LOADED) | |
969 delete_result = DeletePageResult::SUCCESS; | |
970 else | |
971 delete_result = DeletePageResult::STORE_FAILURE; | |
972 | |
973 InformDeletePageDone(callback, delete_result); | |
974 } | |
975 | |
976 void OfflinePageModelImpl::InformDeletePageDone( | |
977 const DeletePageCallback& callback, | |
978 DeletePageResult result) { | |
979 UMA_HISTOGRAM_ENUMERATION("OfflinePages.DeletePageResult", | |
980 static_cast<int>(result), | |
981 static_cast<int>(DeletePageResult::RESULT_COUNT)); | |
982 archive_manager_->GetStorageStats( | |
983 base::Bind(&ReportStorageHistogramsAfterDelete)); | |
984 if (!callback.is_null()) | |
985 callback.Run(result); | |
986 } | |
987 | |
988 void OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths( | |
989 const std::set<base::FilePath>& archive_paths) { | |
990 ExpirePagesMissingArchiveFile(archive_paths); | |
991 DeleteOrphanedArchives(archive_paths); | |
992 } | |
993 | |
994 void OfflinePageModelImpl::ExpirePagesMissingArchiveFile( | |
995 const std::set<base::FilePath>& archive_paths) { | |
996 std::vector<int64_t> ids_of_pages_missing_archive_file; | |
997 for (const auto& id_page_pair : offline_pages_) { | |
998 if (archive_paths.count(id_page_pair.second.file_path) == 0UL) | |
999 ids_of_pages_missing_archive_file.push_back(id_page_pair.first); | |
1000 } | |
1001 | |
1002 if (ids_of_pages_missing_archive_file.empty()) | |
1003 return; | |
1004 | |
1005 ExpirePages( | |
1006 ids_of_pages_missing_archive_file, GetCurrentTime(), | |
1007 base::Bind(&OfflinePageModelImpl::OnExpirePagesMissingArchiveFileDone, | |
1008 weak_ptr_factory_.GetWeakPtr(), | |
1009 ids_of_pages_missing_archive_file)); | |
1010 } | |
1011 | |
1012 void OfflinePageModelImpl::OnExpirePagesMissingArchiveFileDone( | |
1013 const std::vector<int64_t>& offline_ids, | |
1014 bool success) { | |
1015 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.PagesMissingArchiveFileCount", | |
1016 static_cast<int32_t>(offline_ids.size())); | |
1017 UMA_HISTOGRAM_BOOLEAN( | |
1018 "OfflinePages.Consistency.ExpirePagesMissingArchiveFileResult", success); | |
1019 } | |
1020 | |
1021 void OfflinePageModelImpl::DeleteOrphanedArchives( | |
1022 const std::set<base::FilePath>& archive_paths) { | |
1023 // Archives are considered orphaned unless they are pointed to by some pages. | |
1024 std::set<base::FilePath> orphaned_archive_set(archive_paths); | |
1025 for (const auto& id_page_pair : offline_pages_) | |
1026 orphaned_archive_set.erase(id_page_pair.second.file_path); | |
1027 | |
1028 if (orphaned_archive_set.empty()) | |
1029 return; | |
1030 | |
1031 std::vector<base::FilePath> orphaned_archives(orphaned_archive_set.begin(), | |
1032 orphaned_archive_set.end()); | |
1033 archive_manager_->DeleteMultipleArchives( | |
1034 orphaned_archives, | |
1035 base::Bind(&OfflinePageModelImpl::OnDeleteOrphanedArchivesDone, | |
1036 weak_ptr_factory_.GetWeakPtr(), orphaned_archives)); | |
1037 } | |
1038 | |
1039 void OfflinePageModelImpl::OnDeleteOrphanedArchivesDone( | |
1040 const std::vector<base::FilePath>& archives, | |
1041 bool success) { | |
1042 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.OrphanedArchivesCount", | |
1043 static_cast<int32_t>(archives.size())); | |
1044 UMA_HISTOGRAM_BOOLEAN("OfflinePages.Consistency.DeleteOrphanedArchivesResult", | |
1045 success); | |
1046 } | |
1047 | |
1048 void OfflinePageModelImpl::CacheLoadedData( | |
1049 const std::vector<OfflinePageItem>& offline_pages) { | |
1050 offline_pages_.clear(); | |
1051 for (const auto& offline_page : offline_pages) | |
1052 offline_pages_[offline_page.offline_id] = offline_page; | |
1053 } | |
1054 | |
1055 void OfflinePageModelImpl::ClearStorageIfNeeded( | |
1056 const ClearStorageCallback& callback) { | |
1057 storage_manager_->ClearPagesIfNeeded(callback); | |
1058 } | |
1059 | |
1060 void OfflinePageModelImpl::OnStorageCleared(size_t expired_page_count, | |
1061 ClearStorageResult result) { | |
1062 UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearStorageResult", | |
1063 static_cast<int>(result), | |
1064 static_cast<int>(ClearStorageResult::RESULT_COUNT)); | |
1065 if (expired_page_count > 0) { | |
1066 UMA_HISTOGRAM_COUNTS("OfflinePages.ExpirePage.BatchSize", | |
1067 static_cast<int32_t>(expired_page_count)); | |
1068 } | |
1069 } | |
1070 | |
1071 void OfflinePageModelImpl::PostClearStorageIfNeededTask() { | |
1072 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1073 FROM_HERE, base::Bind(&OfflinePageModelImpl::ClearStorageIfNeeded, | |
1074 weak_ptr_factory_.GetWeakPtr(), | |
1075 base::Bind(&OfflinePageModelImpl::OnStorageCleared, | |
1076 weak_ptr_factory_.GetWeakPtr()))); | |
1077 } | |
1078 | |
1079 bool OfflinePageModelImpl::IsRemovedOnCacheReset( | |
1080 const OfflinePageItem& offline_page) const { | |
1081 return policy_controller_->IsRemovedOnCacheReset( | |
1082 offline_page.client_id.name_space); | |
1083 } | |
1084 | |
1085 void OfflinePageModelImpl::RunWhenLoaded(const base::Closure& task) { | |
1086 if (!is_loaded_) { | |
1087 delayed_tasks_.push_back(task); | |
1088 return; | |
1089 } | |
1090 | |
1091 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task); | |
1092 } | |
1093 | |
1094 base::Time OfflinePageModelImpl::GetCurrentTime() const { | |
1095 return testing_clock_ ? testing_clock_->Now() : base::Time::Now(); | |
1096 } | |
1097 | |
1098 } // namespace offline_pages | |
OLD | NEW |