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 ClientPolicyController* policy_controller_, | |
187 const std::map<int64_t, OfflinePageItem>& offline_pages, | |
188 const OfflinePageItem& offline_page, | |
189 const base::Time& save_time) { | |
190 DCHECK(policy_controller_); | |
191 // The histogram below is an expansion of the UMA_HISTOGRAM_TIMES | |
192 // macro adapted to allow for a dynamically suffixed histogram name. | |
193 // Note: The factory creates and owns the histogram. | |
194 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( | |
195 AddHistogramSuffix(offline_page.client_id, "OfflinePages.SavePageTime"), | |
196 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10), | |
197 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
198 histogram->AddTime(save_time - offline_page.creation_time); | |
199 | |
200 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
201 // macro adapted to allow for a dynamically suffixed histogram name. | |
202 // Note: The factory creates and owns the histogram. | |
203 // Reported as Kb between 1Kb and 10Mb. | |
204 histogram = base::Histogram::FactoryGet( | |
205 AddHistogramSuffix(offline_page.client_id, "OfflinePages.PageSize"), | |
206 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
207 histogram->Add(offline_page.file_size / 1024); | |
208 | |
209 if (policy_controller_->IsSupportedByDownload( | |
210 offline_page.client_id.name_space)) { | |
211 int matching_url_count; | |
212 base::TimeDelta time_since_most_recent_duplicate; | |
213 if (GetMatchingURLCountAndMostRecentCreationTime( | |
214 offline_pages, offline_page.client_id.name_space, offline_page.url, | |
215 offline_page.creation_time, &matching_url_count, | |
216 &time_since_most_recent_duplicate)) { | |
217 // Using CUSTOM_COUNTS instead of time-oriented histogram to record | |
218 // samples in seconds rather than milliseconds. | |
219 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
220 "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved", | |
221 time_since_most_recent_duplicate.InSeconds(), | |
222 base::TimeDelta::FromSeconds(1).InSeconds(), | |
223 base::TimeDelta::FromDays(7).InSeconds(), 50); | |
224 } | |
225 UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DownloadSavedPageDuplicateCount", | |
226 matching_url_count, 1, 20, 10); | |
227 } | |
228 } | |
229 | |
230 void ReportPageHistogramsAfterDelete( | |
231 const std::map<int64_t, OfflinePageItem>& offline_pages, | |
232 const std::vector<OfflinePageItem>& deleted_pages, | |
233 const base::Time& delete_time) { | |
234 const int max_minutes = base::TimeDelta::FromDays(365).InMinutes(); | |
235 int64_t total_size = 0; | |
236 | |
237 for (const auto& page : deleted_pages) { | |
238 total_size += page.file_size; | |
239 ClientId client_id = page.client_id; | |
240 | |
241 if (client_id.name_space == kDownloadNamespace) { | |
242 int remaining_pages_with_url; | |
243 GetMatchingURLCountAndMostRecentCreationTime( | |
244 offline_pages, page.client_id.name_space, page.url, base::Time::Max(), | |
245 &remaining_pages_with_url, nullptr); | |
246 UMA_HISTOGRAM_CUSTOM_COUNTS( | |
247 "OfflinePages.DownloadDeletedPageDuplicateCount", | |
248 remaining_pages_with_url, 1, 20, 10); | |
249 } | |
250 | |
251 // The histograms below are an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
252 // macro adapted to allow for a dynamically suffixed histogram name. | |
253 // Note: The factory creates and owns the histogram. | |
254 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
255 AddHistogramSuffix(client_id, "OfflinePages.PageLifetime"), | |
256 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
257 histogram->Add((delete_time - page.creation_time).InMinutes()); | |
258 | |
259 histogram = base::Histogram::FactoryGet( | |
260 AddHistogramSuffix( | |
261 client_id, "OfflinePages.DeletePage.TimeSinceLastOpen"), | |
262 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
263 histogram->Add((delete_time - page.last_access_time).InMinutes()); | |
264 | |
265 histogram = base::Histogram::FactoryGet( | |
266 AddHistogramSuffix( | |
267 client_id, "OfflinePages.DeletePage.LastOpenToCreated"), | |
268 1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag); | |
269 histogram->Add((page.last_access_time - page.creation_time).InMinutes()); | |
270 | |
271 // Reported as Kb between 1Kb and 10Mb. | |
272 histogram = base::Histogram::FactoryGet( | |
273 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.PageSize"), | |
274 1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
275 histogram->Add(page.file_size / 1024); | |
276 | |
277 histogram = base::Histogram::FactoryGet( | |
278 AddHistogramSuffix(client_id, "OfflinePages.DeletePage.AccessCount"), | |
279 1, 1000000, 50, base::HistogramBase::kUmaTargetedHistogramFlag); | |
280 histogram->Add(page.access_count); | |
281 } | |
282 | |
283 if (deleted_pages.size() > 1) { | |
284 UMA_HISTOGRAM_COUNTS("OfflinePages.BatchDelete.Count", | |
285 static_cast<int32_t>(deleted_pages.size())); | |
286 UMA_HISTOGRAM_MEMORY_KB( | |
287 "OfflinePages.BatchDelete.TotalPageSize", total_size / 1024); | |
288 } | |
289 } | |
290 | |
291 void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item, | |
292 const base::Time& access_time) { | |
293 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
294 // macro adapted to allow for a dynamically suffixed histogram name. | |
295 // Note: The factory creates and owns the histogram. | |
296 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
297 AddHistogramSuffix( | |
298 offline_page_item.client_id, | |
299 offline_page_item.access_count == 0 ? | |
300 "OfflinePages.FirstOpenSinceCreated" : | |
301 "OfflinePages.OpenSinceLastOpen"), | |
302 1, kMaxOpenedPageHistogramBucket.InMinutes(), 50, | |
303 base::HistogramBase::kUmaTargetedHistogramFlag); | |
304 histogram->Add( | |
305 (access_time - offline_page_item.last_access_time).InMinutes()); | |
306 } | |
307 | |
308 } // namespace | |
309 | |
310 // protected | |
311 OfflinePageModelImpl::OfflinePageModelImpl() | |
312 : OfflinePageModel(), is_loaded_(false), weak_ptr_factory_(this) {} | |
313 | |
314 OfflinePageModelImpl::OfflinePageModelImpl( | |
315 std::unique_ptr<OfflinePageMetadataStore> store, | |
316 const base::FilePath& archives_dir, | |
317 const scoped_refptr<base::SequencedTaskRunner>& task_runner) | |
318 : store_(std::move(store)), | |
319 archives_dir_(archives_dir), | |
320 is_loaded_(false), | |
321 policy_controller_(new ClientPolicyController()), | |
322 archive_manager_(new ArchiveManager(archives_dir, task_runner)), | |
323 testing_clock_(nullptr), | |
324 weak_ptr_factory_(this) { | |
325 archive_manager_->EnsureArchivesDirCreated( | |
326 base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone, | |
327 weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now())); | |
328 } | |
329 | |
330 OfflinePageModelImpl::~OfflinePageModelImpl() {} | |
331 | |
332 void OfflinePageModelImpl::AddObserver(Observer* observer) { | |
333 observers_.AddObserver(observer); | |
334 } | |
335 | |
336 void OfflinePageModelImpl::RemoveObserver(Observer* observer) { | |
337 observers_.RemoveObserver(observer); | |
338 } | |
339 | |
340 void OfflinePageModelImpl::SavePage( | |
341 const SavePageParams& save_page_params, | |
342 std::unique_ptr<OfflinePageArchiver> archiver, | |
343 const SavePageCallback& callback) { | |
344 DCHECK(is_loaded_); | |
345 | |
346 // Skip saving the page that is not intended to be saved, like local file | |
347 // page. | |
348 if (!OfflinePageModel::CanSaveURL(save_page_params.url)) { | |
349 InformSavePageDone(callback, SavePageResult::SKIPPED, | |
350 save_page_params.client_id, kInvalidOfflineId); | |
351 return; | |
352 } | |
353 | |
354 // The web contents is not available if archiver is not created and passed. | |
355 if (!archiver.get()) { | |
356 InformSavePageDone(callback, SavePageResult::CONTENT_UNAVAILABLE, | |
357 save_page_params.client_id, kInvalidOfflineId); | |
358 return; | |
359 } | |
360 | |
361 // If we already have an offline id, use it. If not, generate one. | |
362 int64_t offline_id = save_page_params.proposed_offline_id; | |
363 if (offline_id == kInvalidOfflineId) | |
364 offline_id = GenerateOfflineId(); | |
365 | |
366 archiver->CreateArchive( | |
367 archives_dir_, offline_id, | |
368 base::Bind(&OfflinePageModelImpl::OnCreateArchiveDone, | |
369 weak_ptr_factory_.GetWeakPtr(), save_page_params, offline_id, | |
370 GetCurrentTime(), callback)); | |
371 pending_archivers_.push_back(std::move(archiver)); | |
372 } | |
373 | |
374 void OfflinePageModelImpl::MarkPageAccessed(int64_t offline_id) { | |
375 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::MarkPageAccessedWhenLoadDone, | |
376 weak_ptr_factory_.GetWeakPtr(), offline_id)); | |
377 } | |
378 | |
379 void OfflinePageModelImpl::MarkPageAccessedWhenLoadDone(int64_t offline_id) { | |
380 DCHECK(is_loaded_); | |
381 | |
382 auto iter = offline_pages_.find(offline_id); | |
383 if (iter == offline_pages_.end()) | |
384 return; | |
385 | |
386 // Make a copy of the cached item and update it. The cached item should only | |
387 // be updated upon the successful store operation. | |
388 OfflinePageItem offline_page_item = iter->second; | |
389 | |
390 ReportPageHistogramsAfterAccess(offline_page_item, GetCurrentTime()); | |
391 | |
392 offline_page_item.last_access_time = GetCurrentTime(); | |
393 offline_page_item.access_count++; | |
394 | |
395 std::vector<OfflinePageItem> items = { offline_page_item }; | |
396 store_->UpdateOfflinePages( | |
397 items, base::Bind(&OfflinePageModelImpl::OnMarkPageAccesseDone, | |
398 weak_ptr_factory_.GetWeakPtr(), offline_page_item)); | |
399 } | |
400 | |
401 void OfflinePageModelImpl::DeletePagesByOfflineId( | |
402 const std::vector<int64_t>& offline_ids, | |
403 const DeletePageCallback& callback) { | |
404 RunWhenLoaded(base::Bind(&OfflinePageModelImpl::DoDeletePagesByOfflineId, | |
405 weak_ptr_factory_.GetWeakPtr(), offline_ids, | |
406 callback)); | |
407 } | |
408 | |
409 void OfflinePageModelImpl::DoDeletePagesByOfflineId( | |
410 const std::vector<int64_t>& offline_ids, | |
411 const DeletePageCallback& callback) { | |
412 DCHECK(is_loaded_); | |
413 | |
414 std::vector<base::FilePath> paths_to_delete; | |
415 for (const auto& offline_id : offline_ids) { | |
416 auto iter = offline_pages_.find(offline_id); | |
417 if (iter != offline_pages_.end()) { | |
418 paths_to_delete.push_back(iter->second.file_path); | |
419 } | |
420 } | |
421 | |
422 // If there're no pages to delete, return early. | |
423 if (paths_to_delete.empty()) { | |
424 InformDeletePageDone(callback, DeletePageResult::SUCCESS); | |
425 return; | |
426 } | |
427 | |
428 archive_manager_->DeleteMultipleArchives( | |
429 paths_to_delete, | |
430 base::Bind(&OfflinePageModelImpl::OnDeleteArchiveFilesDone, | |
431 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback)); | |
432 } | |
433 | |
434 void OfflinePageModelImpl::DeletePagesByClientIds( | |
435 const std::vector<ClientId>& client_ids, | |
436 const DeletePageCallback& callback) { | |
437 OfflinePageModelQueryBuilder builder; | |
438 builder.SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
439 client_ids); | |
440 auto delete_pages = base::Bind(&OfflinePageModelImpl::DeletePages, | |
441 weak_ptr_factory_.GetWeakPtr(), callback); | |
442 RunWhenLoaded(base::Bind( | |
443 &OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
444 weak_ptr_factory_.GetWeakPtr(), | |
445 base::Passed(builder.Build(GetPolicyController())), delete_pages)); | |
446 } | |
447 | |
448 void OfflinePageModelImpl::DeletePages( | |
449 const DeletePageCallback& callback, | |
450 const MultipleOfflinePageItemResult& pages) { | |
451 DCHECK(is_loaded_); | |
452 | |
453 std::vector<int64_t> offline_ids; | |
454 for (auto& page : pages) | |
455 offline_ids.emplace_back(page.offline_id); | |
456 | |
457 DoDeletePagesByOfflineId(offline_ids, callback); | |
458 } | |
459 | |
460 void OfflinePageModelImpl::GetPagesMatchingQuery( | |
461 std::unique_ptr<OfflinePageModelQuery> query, | |
462 const MultipleOfflinePageItemCallback& callback) { | |
463 RunWhenLoaded(base::Bind( | |
464 &OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
465 weak_ptr_factory_.GetWeakPtr(), base::Passed(&query), callback)); | |
466 } | |
467 | |
468 void OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone( | |
469 std::unique_ptr<OfflinePageModelQuery> query, | |
470 const MultipleOfflinePageItemCallback& callback) { | |
471 DCHECK(query); | |
472 DCHECK(is_loaded_); | |
473 | |
474 MultipleOfflinePageItemResult offline_pages_result; | |
475 | |
476 for (const auto& id_page_pair : offline_pages_) { | |
477 if (query->Matches(id_page_pair.second)) | |
478 offline_pages_result.emplace_back(id_page_pair.second); | |
479 } | |
480 | |
481 callback.Run(offline_pages_result); | |
482 } | |
483 | |
484 void OfflinePageModelImpl::GetPagesByClientIds( | |
485 const std::vector<ClientId>& client_ids, | |
486 const MultipleOfflinePageItemCallback& callback) { | |
487 OfflinePageModelQueryBuilder builder; | |
488 builder.SetClientIds(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
489 client_ids); | |
490 RunWhenLoaded( | |
491 base::Bind(&OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
492 weak_ptr_factory_.GetWeakPtr(), | |
493 base::Passed(builder.Build(GetPolicyController())), callback)); | |
494 } | |
495 | |
496 void OfflinePageModelImpl::DeleteCachedPagesByURLPredicate( | |
497 const UrlPredicate& predicate, | |
498 const DeletePageCallback& callback) { | |
499 RunWhenLoaded( | |
500 base::Bind(&OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate, | |
501 weak_ptr_factory_.GetWeakPtr(), predicate, callback)); | |
502 } | |
503 | |
504 void OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate( | |
505 const UrlPredicate& predicate, | |
506 const DeletePageCallback& callback) { | |
507 DCHECK(is_loaded_); | |
508 | |
509 std::vector<int64_t> offline_ids; | |
510 for (const auto& id_page_pair : offline_pages_) { | |
511 if (IsRemovedOnCacheReset(id_page_pair.second) && | |
512 predicate.Run(id_page_pair.second.url)) { | |
513 offline_ids.push_back(id_page_pair.first); | |
514 } | |
515 } | |
516 DoDeletePagesByOfflineId(offline_ids, callback); | |
517 } | |
518 | |
519 void OfflinePageModelImpl::CheckPagesExistOffline( | |
520 const std::set<GURL>& urls, | |
521 const CheckPagesExistOfflineCallback& callback) { | |
522 OfflinePageModelQueryBuilder builder; | |
523 builder | |
524 .SetUrls(OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, | |
525 std::vector<GURL>(urls.begin(), urls.end())) | |
526 .RequireRestrictedToOriginalTab( | |
527 OfflinePageModelQueryBuilder::Requirement::EXCLUDE_MATCHING); | |
528 auto pages_to_urls = base::Bind( | |
529 [](const CheckPagesExistOfflineCallback& callback, | |
530 const MultipleOfflinePageItemResult& pages) { | |
531 CheckPagesExistOfflineResult result; | |
532 for (auto& page : pages) | |
533 result.insert(page.url); | |
534 callback.Run(result); | |
535 }, | |
536 callback); | |
537 RunWhenLoaded(base::Bind( | |
538 &OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
539 weak_ptr_factory_.GetWeakPtr(), | |
540 base::Passed(builder.Build(GetPolicyController())), pages_to_urls)); | |
541 } | |
542 | |
543 void OfflinePageModelImpl::GetAllPages( | |
544 const MultipleOfflinePageItemCallback& callback) { | |
545 OfflinePageModelQueryBuilder builder; | |
546 RunWhenLoaded( | |
547 base::Bind(&OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
548 weak_ptr_factory_.GetWeakPtr(), | |
549 base::Passed(builder.Build(GetPolicyController())), callback)); | |
550 } | |
551 | |
552 void OfflinePageModelImpl::GetOfflineIdsForClientId( | |
553 const ClientId& client_id, | |
554 const MultipleOfflineIdCallback& callback) { | |
555 RunWhenLoaded( | |
556 base::Bind(&OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone, | |
557 weak_ptr_factory_.GetWeakPtr(), client_id, callback)); | |
558 } | |
559 | |
560 void OfflinePageModelImpl::GetOfflineIdsForClientIdWhenLoadDone( | |
561 const ClientId& client_id, | |
562 const MultipleOfflineIdCallback& callback) const { | |
563 DCHECK(is_loaded_); | |
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 results.push_back(id_page_pair.second.offline_id); | |
577 } | |
578 return results; | |
579 } | |
580 | |
581 void OfflinePageModelImpl::GetPageByOfflineId( | |
582 int64_t offline_id, | |
583 const SingleOfflinePageItemCallback& callback) { | |
584 std::vector<int64_t> query_ids; | |
585 query_ids.emplace_back(offline_id); | |
586 | |
587 OfflinePageModelQueryBuilder builder; | |
588 builder.SetOfflinePageIds( | |
589 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING, query_ids); | |
590 | |
591 auto multiple_callback = base::Bind( | |
592 [](const SingleOfflinePageItemCallback& callback, | |
593 const MultipleOfflinePageItemResult& result) { | |
594 DCHECK_LE(result.size(), 1U); | |
595 if (result.empty()) { | |
596 callback.Run(nullptr); | |
597 } else { | |
598 callback.Run(&result[0]); | |
599 } | |
600 }, | |
601 callback); | |
602 | |
603 RunWhenLoaded(base::Bind( | |
604 &OfflinePageModelImpl::GetPagesMatchingQueryWhenLoadDone, | |
605 weak_ptr_factory_.GetWeakPtr(), | |
606 base::Passed(builder.Build(GetPolicyController())), multiple_callback)); | |
607 } | |
608 | |
609 void OfflinePageModelImpl::GetPagesByURL( | |
610 const GURL& url, | |
611 URLSearchMode url_search_mode, | |
612 const MultipleOfflinePageItemCallback& callback) { | |
613 RunWhenLoaded( | |
614 base::Bind(&OfflinePageModelImpl::GetPagesByURLWhenLoadDone, | |
615 weak_ptr_factory_.GetWeakPtr(), url, | |
616 url_search_mode, callback)); | |
617 } | |
618 | |
619 void OfflinePageModelImpl::GetPagesByURLWhenLoadDone( | |
620 const GURL& url, | |
621 URLSearchMode url_search_mode, | |
622 const MultipleOfflinePageItemCallback& callback) const { | |
623 DCHECK(is_loaded_); | |
624 std::vector<OfflinePageItem> result; | |
625 | |
626 GURL::Replacements remove_params; | |
627 remove_params.ClearRef(); | |
628 | |
629 GURL url_without_fragment = | |
630 url.ReplaceComponents(remove_params); | |
631 | |
632 for (const auto& id_page_pair : offline_pages_) { | |
633 // First, search by last committed URL with fragment stripped. | |
634 if (url_without_fragment == | |
635 id_page_pair.second.url.ReplaceComponents(remove_params)) { | |
636 result.push_back(id_page_pair.second); | |
637 continue; | |
638 } | |
639 // Then, search by original request URL if |url_search_mode| wants it. | |
640 // Note that we want to do the exact match with fragment included. This is | |
641 // because original URL is used for redirect purpose and it is always safer | |
642 // to support the exact redirect. | |
643 if (url_search_mode == URLSearchMode::SEARCH_BY_ALL_URLS && | |
644 url == id_page_pair.second.original_url) { | |
645 result.push_back(id_page_pair.second); | |
646 } | |
647 } | |
648 | |
649 callback.Run(result); | |
650 } | |
651 | |
652 void OfflinePageModelImpl::CheckMetadataConsistency() { | |
653 archive_manager_->GetAllArchives( | |
654 base::Bind(&OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths, | |
655 weak_ptr_factory_.GetWeakPtr())); | |
656 } | |
657 | |
658 ClientPolicyController* OfflinePageModelImpl::GetPolicyController() { | |
659 return policy_controller_.get(); | |
660 } | |
661 | |
662 OfflinePageMetadataStore* OfflinePageModelImpl::GetStoreForTesting() { | |
663 return store_.get(); | |
664 } | |
665 | |
666 OfflinePageStorageManager* OfflinePageModelImpl::GetStorageManager() { | |
667 return storage_manager_.get(); | |
668 } | |
669 | |
670 bool OfflinePageModelImpl::is_loaded() const { | |
671 return is_loaded_; | |
672 } | |
673 | |
674 OfflineEventLogger* OfflinePageModelImpl::GetLogger() { | |
675 return &offline_event_logger_; | |
676 } | |
677 | |
678 void OfflinePageModelImpl::OnCreateArchiveDone( | |
679 const SavePageParams& save_page_params, | |
680 int64_t offline_id, | |
681 const base::Time& start_time, | |
682 const SavePageCallback& callback, | |
683 OfflinePageArchiver* archiver, | |
684 ArchiverResult archiver_result, | |
685 const GURL& url, | |
686 const base::FilePath& file_path, | |
687 const base::string16& title, | |
688 int64_t file_size) { | |
689 if (save_page_params.url != url) { | |
690 DVLOG(1) << "Saved URL does not match requested URL."; | |
691 // TODO(fgorski): We have created an archive for a wrong URL. It should be | |
692 // deleted from here, once archiver has the right functionality. | |
693 InformSavePageDone(callback, SavePageResult::ARCHIVE_CREATION_FAILED, | |
694 save_page_params.client_id, offline_id); | |
695 DeletePendingArchiver(archiver); | |
696 return; | |
697 } | |
698 | |
699 if (archiver_result != ArchiverResult::SUCCESSFULLY_CREATED) { | |
700 SavePageResult result = ToSavePageResult(archiver_result); | |
701 InformSavePageDone( | |
702 callback, result, save_page_params.client_id, offline_id); | |
703 DeletePendingArchiver(archiver); | |
704 return; | |
705 } | |
706 OfflinePageItem offline_page_item(url, offline_id, save_page_params.client_id, | |
707 file_path, file_size, start_time); | |
708 offline_page_item.title = title; | |
709 offline_page_item.original_url = save_page_params.original_url; | |
710 store_->AddOfflinePage(offline_page_item, | |
711 base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone, | |
712 weak_ptr_factory_.GetWeakPtr(), archiver, | |
713 callback, offline_page_item)); | |
714 } | |
715 | |
716 void OfflinePageModelImpl::OnAddOfflinePageDone( | |
717 OfflinePageArchiver* archiver, | |
718 const SavePageCallback& callback, | |
719 const OfflinePageItem& offline_page, | |
720 ItemActionStatus status) { | |
721 SavePageResult result; | |
722 if (status == ItemActionStatus::SUCCESS) { | |
723 offline_pages_[offline_page.offline_id] = offline_page; | |
724 result = SavePageResult::SUCCESS; | |
725 ReportPageHistogramAfterSave(policy_controller_.get(), offline_pages_, | |
726 offline_page, GetCurrentTime()); | |
727 offline_event_logger_.RecordPageSaved( | |
728 offline_page.client_id.name_space, offline_page.url.spec(), | |
729 std::to_string(offline_page.offline_id)); | |
730 } else if (status == ItemActionStatus::ALREADY_EXISTS) { | |
731 result = SavePageResult::ALREADY_EXISTS; | |
732 } else { | |
733 result = SavePageResult::STORE_FAILURE; | |
734 } | |
735 InformSavePageDone(callback, result, offline_page.client_id, | |
736 offline_page.offline_id); | |
737 if (result == SavePageResult::SUCCESS) { | |
738 DeleteExistingPagesWithSameURL(offline_page); | |
739 } else { | |
740 PostClearStorageIfNeededTask(false /* delayed */); | |
741 } | |
742 | |
743 DeletePendingArchiver(archiver); | |
744 for (Observer& observer : observers_) | |
745 observer.OfflinePageModelChanged(this); | |
746 } | |
747 | |
748 void OfflinePageModelImpl::OnMarkPageAccesseDone( | |
749 const OfflinePageItem& offline_page_item, | |
750 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
751 // Update the item in the cache only upon success. | |
752 if (result->updated_items.size() > 0) | |
753 offline_pages_[offline_page_item.offline_id] = offline_page_item; | |
754 | |
755 // No need to fire OfflinePageModelChanged event since updating access info | |
756 // should not have any impact to the UI. | |
757 } | |
758 | |
759 void OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone( | |
760 const base::TimeTicks& start_time) { | |
761 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime", | |
762 base::TimeTicks::Now() - start_time); | |
763 | |
764 const int kResetAttemptsLeft = 1; | |
765 store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized, | |
766 weak_ptr_factory_.GetWeakPtr(), start_time, | |
767 kResetAttemptsLeft)); | |
768 } | |
769 | |
770 void OfflinePageModelImpl::OnStoreInitialized(const base::TimeTicks& start_time, | |
771 int reset_attempts_left, | |
772 bool success) { | |
773 if (success) { | |
774 DCHECK_EQ(store_->state(), StoreState::LOADED); | |
775 store_->GetOfflinePages( | |
776 base::Bind(&OfflinePageModelImpl::OnInitialGetOfflinePagesDone, | |
777 weak_ptr_factory_.GetWeakPtr(), start_time)); | |
778 return; | |
779 } | |
780 | |
781 DCHECK_EQ(store_->state(), StoreState::FAILED_LOADING); | |
782 // If there are no more reset attempts left, stop here. | |
783 if (reset_attempts_left == 0) { | |
784 FinalizeModelLoad(); | |
785 return; | |
786 } | |
787 | |
788 // Otherwise reduce the remaining attempts counter and reset store. | |
789 store_->Reset(base::Bind(&OfflinePageModelImpl::OnStoreResetDone, | |
790 weak_ptr_factory_.GetWeakPtr(), start_time, | |
791 reset_attempts_left - 1)); | |
792 } | |
793 | |
794 void OfflinePageModelImpl::OnStoreResetDone(const base::TimeTicks& start_time, | |
795 int reset_attempts_left, | |
796 bool success) { | |
797 if (success) { | |
798 DCHECK_EQ(store_->state(), StoreState::NOT_LOADED); | |
799 store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized, | |
800 weak_ptr_factory_.GetWeakPtr(), start_time, | |
801 reset_attempts_left)); | |
802 return; | |
803 } | |
804 | |
805 DCHECK_EQ(store_->state(), StoreState::FAILED_RESET); | |
806 FinalizeModelLoad(); | |
807 } | |
808 | |
809 void OfflinePageModelImpl::OnInitialGetOfflinePagesDone( | |
810 const base::TimeTicks& start_time, | |
811 const std::vector<OfflinePageItem>& offline_pages) { | |
812 DCHECK(!is_loaded_); | |
813 | |
814 UMA_HISTOGRAM_TIMES("OfflinePages.Model.ConstructionToLoadedEventTime", | |
815 base::TimeTicks::Now() - start_time); | |
816 | |
817 CacheLoadedData(offline_pages); | |
818 FinalizeModelLoad(); | |
819 | |
820 // Ensure necessary cleanup operations are started. | |
821 CheckMetadataConsistency(); | |
822 } | |
823 | |
824 void OfflinePageModelImpl::FinalizeModelLoad() { | |
825 is_loaded_ = true; | |
826 | |
827 // All actions below are meant to be taken regardless of successful load of | |
828 // the store. | |
829 | |
830 // Inform observers the load is done. | |
831 for (Observer& observer : observers_) | |
832 observer.OfflinePageModelLoaded(this); | |
833 | |
834 // Run all the delayed tasks. | |
835 for (const auto& delayed_task : delayed_tasks_) | |
836 delayed_task.Run(); | |
837 delayed_tasks_.clear(); | |
838 | |
839 // Clear storage. | |
840 PostClearStorageIfNeededTask(true /* delayed */); | |
841 } | |
842 | |
843 void OfflinePageModelImpl::InformSavePageDone(const SavePageCallback& callback, | |
844 SavePageResult result, | |
845 const ClientId& client_id, | |
846 int64_t offline_id) { | |
847 ReportSavePageResultHistogramAfterSave(client_id, result); | |
848 archive_manager_->GetStorageStats( | |
849 base::Bind(&ReportStorageHistogramsAfterSave)); | |
850 callback.Run(result, offline_id); | |
851 } | |
852 | |
853 void OfflinePageModelImpl::DeleteExistingPagesWithSameURL( | |
854 const OfflinePageItem& offline_page) { | |
855 // Remove existing pages generated by the same policy and with same url. | |
856 size_t pages_allowed = | |
857 policy_controller_->GetPolicy(offline_page.client_id.name_space) | |
858 .pages_allowed_per_url; | |
859 if (pages_allowed == kUnlimitedPages) | |
860 return; | |
861 GetPagesByURL( | |
862 offline_page.url, | |
863 URLSearchMode::SEARCH_BY_FINAL_URL_ONLY, | |
864 base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL, | |
865 weak_ptr_factory_.GetWeakPtr(), offline_page, pages_allowed)); | |
866 } | |
867 | |
868 void OfflinePageModelImpl::OnPagesFoundWithSameURL( | |
869 const OfflinePageItem& offline_page, | |
870 size_t pages_allowed, | |
871 const MultipleOfflinePageItemResult& items) { | |
872 std::vector<OfflinePageItem> pages_to_delete; | |
873 for (const auto& item : items) { | |
874 if (item.offline_id != offline_page.offline_id && | |
875 item.client_id.name_space == offline_page.client_id.name_space) { | |
876 pages_to_delete.push_back(item); | |
877 } | |
878 } | |
879 // Only keep |pages_allowed|-1 of most fresh pages and delete others, by | |
880 // sorting pages with the oldest ones first and resize the vector. | |
881 if (pages_to_delete.size() >= pages_allowed) { | |
882 sort(pages_to_delete.begin(), pages_to_delete.end(), | |
883 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool { | |
884 return a.last_access_time < b.last_access_time; | |
885 }); | |
886 pages_to_delete.resize(pages_to_delete.size() - pages_allowed + 1); | |
887 } | |
888 std::vector<int64_t> page_ids_to_delete; | |
889 for (const auto& item : pages_to_delete) | |
890 page_ids_to_delete.push_back(item.offline_id); | |
891 DeletePagesByOfflineId( | |
892 page_ids_to_delete, | |
893 base::Bind(&OfflinePageModelImpl::OnDeleteOldPagesWithSameURL, | |
894 weak_ptr_factory_.GetWeakPtr())); | |
895 } | |
896 | |
897 void OfflinePageModelImpl::OnDeleteOldPagesWithSameURL( | |
898 DeletePageResult result) { | |
899 // TODO(romax) Add UMAs for failure cases. | |
900 PostClearStorageIfNeededTask(false /* delayed */); | |
901 } | |
902 | |
903 void OfflinePageModelImpl::DeletePendingArchiver( | |
904 OfflinePageArchiver* archiver) { | |
905 pending_archivers_.erase(std::find(pending_archivers_.begin(), | |
906 pending_archivers_.end(), archiver)); | |
907 } | |
908 | |
909 void OfflinePageModelImpl::OnDeleteArchiveFilesDone( | |
910 const std::vector<int64_t>& offline_ids, | |
911 const DeletePageCallback& callback, | |
912 bool success) { | |
913 if (!success) { | |
914 InformDeletePageDone(callback, DeletePageResult::DEVICE_FAILURE); | |
915 return; | |
916 } | |
917 | |
918 store_->RemoveOfflinePages( | |
919 offline_ids, base::Bind(&OfflinePageModelImpl::OnRemoveOfflinePagesDone, | |
920 weak_ptr_factory_.GetWeakPtr(), callback)); | |
921 } | |
922 | |
923 void OfflinePageModelImpl::OnRemoveOfflinePagesDone( | |
924 const DeletePageCallback& callback, | |
925 std::unique_ptr<OfflinePagesUpdateResult> result) { | |
926 ReportPageHistogramsAfterDelete(offline_pages_, result->updated_items, | |
927 GetCurrentTime()); | |
928 | |
929 // This part of the loop is explicitly broken out, as it should be gone in | |
930 // fully asynchronous code. | |
931 for (const auto& page : result->updated_items) { | |
932 int64_t offline_id = page.offline_id; | |
933 offline_event_logger_.RecordPageDeleted(std::to_string(offline_id)); | |
934 auto iter = offline_pages_.find(offline_id); | |
935 if (iter == offline_pages_.end()) | |
936 continue; | |
937 offline_pages_.erase(iter); | |
938 } | |
939 | |
940 for (const auto& page : result->updated_items) { | |
941 for (Observer& observer : observers_) | |
942 observer.OfflinePageDeleted(page.offline_id, page.client_id); | |
943 } | |
944 | |
945 // TODO(fgorski): React the FAILED_INITIALIZATION, FAILED_RESET here. | |
946 // TODO(fgorski): We need a better callback interface for the Remove action on | |
947 // the this class. Currently removing an item that does not exist is | |
948 // considered a success, but not called out as such to the caller. | |
949 DeletePageResult delete_result; | |
950 if (result->store_state == StoreState::LOADED) | |
951 delete_result = DeletePageResult::SUCCESS; | |
952 else | |
953 delete_result = DeletePageResult::STORE_FAILURE; | |
954 | |
955 InformDeletePageDone(callback, delete_result); | |
956 } | |
957 | |
958 void OfflinePageModelImpl::InformDeletePageDone( | |
959 const DeletePageCallback& callback, | |
960 DeletePageResult result) { | |
961 UMA_HISTOGRAM_ENUMERATION("OfflinePages.DeletePageResult", | |
962 static_cast<int>(result), | |
963 static_cast<int>(DeletePageResult::RESULT_COUNT)); | |
964 archive_manager_->GetStorageStats( | |
965 base::Bind(&ReportStorageHistogramsAfterDelete)); | |
966 if (!callback.is_null()) | |
967 callback.Run(result); | |
968 } | |
969 | |
970 void OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths( | |
971 const std::set<base::FilePath>& archive_paths) { | |
972 DeletePagesMissingArchiveFile(archive_paths); | |
973 DeleteOrphanedArchives(archive_paths); | |
974 } | |
975 | |
976 void OfflinePageModelImpl::DeletePagesMissingArchiveFile( | |
977 const std::set<base::FilePath>& archive_paths) { | |
978 std::vector<int64_t> ids_of_pages_missing_archive_file; | |
979 for (const auto& id_page_pair : offline_pages_) { | |
980 if (archive_paths.count(id_page_pair.second.file_path) == 0UL) | |
981 ids_of_pages_missing_archive_file.push_back(id_page_pair.first); | |
982 } | |
983 | |
984 if (ids_of_pages_missing_archive_file.empty()) | |
985 return; | |
986 | |
987 DeletePagesByOfflineId( | |
988 ids_of_pages_missing_archive_file, | |
989 base::Bind(&OfflinePageModelImpl::OnDeletePagesMissingArchiveFileDone, | |
990 weak_ptr_factory_.GetWeakPtr(), | |
991 ids_of_pages_missing_archive_file)); | |
992 } | |
993 | |
994 void OfflinePageModelImpl::OnDeletePagesMissingArchiveFileDone( | |
995 const std::vector<int64_t>& offline_ids, | |
996 DeletePageResult result) { | |
997 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.PagesMissingArchiveFileCount", | |
998 static_cast<int32_t>(offline_ids.size())); | |
999 UMA_HISTOGRAM_ENUMERATION( | |
1000 "OfflinePages.Consistency.DeletePagesMissingArchiveFileResult", | |
1001 static_cast<int>(result), | |
1002 static_cast<int>(DeletePageResult::RESULT_COUNT)); | |
1003 } | |
1004 | |
1005 void OfflinePageModelImpl::DeleteOrphanedArchives( | |
1006 const std::set<base::FilePath>& archive_paths) { | |
1007 // Archives are considered orphaned unless they are pointed to by some pages. | |
1008 std::set<base::FilePath> orphaned_archive_set(archive_paths); | |
1009 for (const auto& id_page_pair : offline_pages_) | |
1010 orphaned_archive_set.erase(id_page_pair.second.file_path); | |
1011 | |
1012 if (orphaned_archive_set.empty()) | |
1013 return; | |
1014 | |
1015 std::vector<base::FilePath> orphaned_archives(orphaned_archive_set.begin(), | |
1016 orphaned_archive_set.end()); | |
1017 archive_manager_->DeleteMultipleArchives( | |
1018 orphaned_archives, | |
1019 base::Bind(&OfflinePageModelImpl::OnDeleteOrphanedArchivesDone, | |
1020 weak_ptr_factory_.GetWeakPtr(), orphaned_archives)); | |
1021 } | |
1022 | |
1023 void OfflinePageModelImpl::OnDeleteOrphanedArchivesDone( | |
1024 const std::vector<base::FilePath>& archives, | |
1025 bool success) { | |
1026 UMA_HISTOGRAM_COUNTS("OfflinePages.Consistency.OrphanedArchivesCount", | |
1027 static_cast<int32_t>(archives.size())); | |
1028 UMA_HISTOGRAM_BOOLEAN("OfflinePages.Consistency.DeleteOrphanedArchivesResult", | |
1029 success); | |
1030 } | |
1031 | |
1032 void OfflinePageModelImpl::CacheLoadedData( | |
1033 const std::vector<OfflinePageItem>& offline_pages) { | |
1034 offline_pages_.clear(); | |
1035 for (const auto& offline_page : offline_pages) | |
1036 offline_pages_[offline_page.offline_id] = offline_page; | |
1037 } | |
1038 | |
1039 void OfflinePageModelImpl::ClearStorageIfNeeded( | |
1040 const ClearStorageCallback& callback) { | |
1041 // Create Storage Manager if necessary. | |
1042 if (!storage_manager_) { | |
1043 storage_manager_.reset(new OfflinePageStorageManager( | |
1044 this, GetPolicyController(), archive_manager_.get())); | |
1045 } | |
1046 storage_manager_->ClearPagesIfNeeded(callback); | |
1047 } | |
1048 | |
1049 void OfflinePageModelImpl::OnStorageCleared(size_t deleted_page_count, | |
1050 ClearStorageResult result) { | |
1051 UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearStorageResult", | |
1052 static_cast<int>(result), | |
1053 static_cast<int>(ClearStorageResult::RESULT_COUNT)); | |
1054 if (deleted_page_count > 0) { | |
1055 UMA_HISTOGRAM_COUNTS("OfflinePages.ClearStorageBatchSize", | |
1056 static_cast<int32_t>(deleted_page_count)); | |
1057 } | |
1058 } | |
1059 | |
1060 void OfflinePageModelImpl::PostClearStorageIfNeededTask(bool delayed) { | |
1061 base::TimeDelta delay = | |
1062 delayed ? kStorageManagerStartingDelay : base::TimeDelta(); | |
1063 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
1064 FROM_HERE, base::Bind(&OfflinePageModelImpl::ClearStorageIfNeeded, | |
1065 weak_ptr_factory_.GetWeakPtr(), | |
1066 base::Bind(&OfflinePageModelImpl::OnStorageCleared, | |
1067 weak_ptr_factory_.GetWeakPtr())), | |
1068 delay); | |
1069 } | |
1070 | |
1071 bool OfflinePageModelImpl::IsRemovedOnCacheReset( | |
1072 const OfflinePageItem& offline_page) const { | |
1073 return policy_controller_->IsRemovedOnCacheReset( | |
1074 offline_page.client_id.name_space); | |
1075 } | |
1076 | |
1077 void OfflinePageModelImpl::RunWhenLoaded(const base::Closure& task) { | |
1078 if (!is_loaded_) { | |
1079 delayed_tasks_.push_back(task); | |
1080 return; | |
1081 } | |
1082 | |
1083 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task); | |
1084 } | |
1085 | |
1086 base::Time OfflinePageModelImpl::GetCurrentTime() const { | |
1087 return testing_clock_ ? testing_clock_->Now() : base::Time::Now(); | |
1088 } | |
1089 | |
1090 } // namespace offline_pages | |
OLD | NEW |