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

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

Issue 1367063004: Support undoing offline page deletion (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: One more change Created 5 years, 2 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> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
14 #include "base/sequenced_task_runner.h" 14 #include "base/sequenced_task_runner.h"
15 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h" 16 #include "base/time/time.h"
16 #include "components/bookmarks/browser/bookmark_model.h" 17 #include "components/bookmarks/browser/bookmark_model.h"
17 #include "components/bookmarks/browser/bookmark_node.h" 18 #include "components/bookmarks/browser/bookmark_node.h"
18 #include "components/offline_pages/offline_page_item.h" 19 #include "components/offline_pages/offline_page_item.h"
19 #include "components/offline_pages/offline_page_metadata_store.h" 20 #include "components/offline_pages/offline_page_metadata_store.h"
20 #include "url/gurl.h" 21 #include "url/gurl.h"
21 22
22 using ArchiverResult = offline_pages::OfflinePageArchiver::ArchiverResult; 23 using ArchiverResult = offline_pages::OfflinePageArchiver::ArchiverResult;
23 using SavePageResult = offline_pages::OfflinePageModel::SavePageResult; 24 using SavePageResult = offline_pages::OfflinePageModel::SavePageResult;
24 25
25 namespace offline_pages { 26 namespace offline_pages {
26 27
27 namespace { 28 namespace {
28 29
29 // Threshold for how old offline copy of a page should be before we offer to 30 // Threshold for how old offline copy of a page should be before we offer to
30 // delete it to free up space. 31 // delete it to free up space.
31 const base::TimeDelta kPageCleanUpThreshold = base::TimeDelta::FromDays(30); 32 const base::TimeDelta kPageCleanUpThreshold = base::TimeDelta::FromDays(30);
32 33
34 // The delay for the final deletion to kick in after the page is marked for
35 // deletion. The value set here is a bit longer that the duration of the
36 // snackbar that offers undo.
37 const base::TimeDelta kFinalDeletionDelay = base::TimeDelta::FromSeconds(6);
38
33 SavePageResult ToSavePageResult(ArchiverResult archiver_result) { 39 SavePageResult ToSavePageResult(ArchiverResult archiver_result) {
34 SavePageResult result; 40 SavePageResult result;
35 switch (archiver_result) { 41 switch (archiver_result) {
36 case ArchiverResult::SUCCESSFULLY_CREATED: 42 case ArchiverResult::SUCCESSFULLY_CREATED:
37 result = SavePageResult::SUCCESS; 43 result = SavePageResult::SUCCESS;
38 break; 44 break;
39 case ArchiverResult::ERROR_DEVICE_FULL: 45 case ArchiverResult::ERROR_DEVICE_FULL:
40 result = SavePageResult::DEVICE_FULL; 46 result = SavePageResult::DEVICE_FULL;
41 break; 47 break;
42 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE: 48 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE:
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 if (iter == offline_pages_.end()) 124 if (iter == offline_pages_.end())
119 return; 125 return;
120 126
121 // Make a copy of the cached item and update it. The cached item should only 127 // Make a copy of the cached item and update it. The cached item should only
122 // be updated upon the successful store operation. 128 // be updated upon the successful store operation.
123 OfflinePageItem offline_page_item = iter->second; 129 OfflinePageItem offline_page_item = iter->second;
124 offline_page_item.last_access_time = base::Time::Now(); 130 offline_page_item.last_access_time = base::Time::Now();
125 offline_page_item.access_count++; 131 offline_page_item.access_count++;
126 store_->AddOrUpdateOfflinePage( 132 store_->AddOrUpdateOfflinePage(
127 offline_page_item, 133 offline_page_item,
128 base::Bind(&OfflinePageModel::OnUpdateOfflinePageDone, 134 base::Bind(&OfflinePageModel::OnMarkPageAccesseDone,
129 weak_ptr_factory_.GetWeakPtr(), offline_page_item)); 135 weak_ptr_factory_.GetWeakPtr(), offline_page_item));
130 } 136 }
131 137
138 void OfflinePageModel::MarkPageForDeletion(int64 bookmark_id,
139 const DeletePageCallback& callback) {
140 DCHECK(is_loaded_);
141 auto iter = offline_pages_.find(bookmark_id);
142 if (iter == offline_pages_.end()) {
143 InformDeletePageDone(callback, DeletePageResult::NOT_FOUND);
144 return;
145 }
146
147 // Make a copy of the cached item and update it. The cached item should only
148 // be updated upon the successful store operation.
149 OfflinePageItem offline_page_item = iter->second;
150 offline_page_item.MarkForDeletion();
151 store_->AddOrUpdateOfflinePage(
152 offline_page_item,
153 base::Bind(&OfflinePageModel::OnMarkPageForDeletionDone,
154 weak_ptr_factory_.GetWeakPtr(), offline_page_item, callback));
155 }
156
132 void OfflinePageModel::DeletePageByBookmarkId( 157 void OfflinePageModel::DeletePageByBookmarkId(
133 int64 bookmark_id, 158 int64 bookmark_id,
134 const DeletePageCallback& callback) { 159 const DeletePageCallback& callback) {
135 DCHECK(is_loaded_); 160 DCHECK(is_loaded_);
136 std::vector<int64> bookmark_ids_to_delete; 161 std::vector<int64> bookmark_ids_to_delete;
137 bookmark_ids_to_delete.push_back(bookmark_id); 162 bookmark_ids_to_delete.push_back(bookmark_id);
138 DeletePagesByBookmarkId(bookmark_ids_to_delete, callback); 163 DeletePagesByBookmarkId(bookmark_ids_to_delete, callback);
139 } 164 }
140 165
141 void OfflinePageModel::DeletePagesByBookmarkId( 166 void OfflinePageModel::DeletePagesByBookmarkId(
(...skipping 21 matching lines...) Expand all
163 base::Bind(&OfflinePageModel::OnDeleteArchiveFilesDone, 188 base::Bind(&OfflinePageModel::OnDeleteArchiveFilesDone,
164 weak_ptr_factory_.GetWeakPtr(), 189 weak_ptr_factory_.GetWeakPtr(),
165 bookmark_ids, 190 bookmark_ids,
166 callback, 191 callback,
167 base::Owned(success))); 192 base::Owned(success)));
168 } 193 }
169 194
170 const std::vector<OfflinePageItem> OfflinePageModel::GetAllPages() const { 195 const std::vector<OfflinePageItem> OfflinePageModel::GetAllPages() const {
171 DCHECK(is_loaded_); 196 DCHECK(is_loaded_);
172 std::vector<OfflinePageItem> offline_pages; 197 std::vector<OfflinePageItem> offline_pages;
173 for (const auto& id_page_pair : offline_pages_) 198 for (const auto& id_page_pair : offline_pages_) {
199 if (id_page_pair.second.IsMarkedForDeletion())
200 continue;
174 offline_pages.push_back(id_page_pair.second); 201 offline_pages.push_back(id_page_pair.second);
202 }
175 return offline_pages; 203 return offline_pages;
176 } 204 }
177 205
178 const std::vector<OfflinePageItem> OfflinePageModel::GetPagesToCleanUp() const { 206 const std::vector<OfflinePageItem> OfflinePageModel::GetPagesToCleanUp() const {
179 DCHECK(is_loaded_); 207 DCHECK(is_loaded_);
180 std::vector<OfflinePageItem> offline_pages; 208 std::vector<OfflinePageItem> offline_pages;
181 base::Time now = base::Time::Now(); 209 base::Time now = base::Time::Now();
182 for (const auto& id_page_pair : offline_pages_) { 210 for (const auto& id_page_pair : offline_pages_) {
183 if (now - id_page_pair.second.last_access_time > kPageCleanUpThreshold) 211 if (!id_page_pair.second.IsMarkedForDeletion() &&
212 now - id_page_pair.second.last_access_time > kPageCleanUpThreshold) {
184 offline_pages.push_back(id_page_pair.second); 213 offline_pages.push_back(id_page_pair.second);
214 }
185 } 215 }
186 return offline_pages; 216 return offline_pages;
187 } 217 }
188 218
189 const OfflinePageItem* OfflinePageModel::GetPageByBookmarkId( 219 const OfflinePageItem* OfflinePageModel::GetPageByBookmarkId(
190 int64 bookmark_id) const { 220 int64 bookmark_id) const {
191 const auto iter = offline_pages_.find(bookmark_id); 221 const auto iter = offline_pages_.find(bookmark_id);
192 return iter != offline_pages_.end() ? &(iter->second) : nullptr; 222 return iter != offline_pages_.end() ? &(iter->second) : nullptr;
193 } 223 }
194 224
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 if (success) { 278 if (success) {
249 offline_pages_[offline_page.bookmark_id] = offline_page; 279 offline_pages_[offline_page.bookmark_id] = offline_page;
250 result = SavePageResult::SUCCESS; 280 result = SavePageResult::SUCCESS;
251 UMA_HISTOGRAM_MEMORY_KB( 281 UMA_HISTOGRAM_MEMORY_KB(
252 "OfflinePages.PageSize", offline_page.file_size / 1024); 282 "OfflinePages.PageSize", offline_page.file_size / 1024);
253 } else { 283 } else {
254 result = SavePageResult::STORE_FAILURE; 284 result = SavePageResult::STORE_FAILURE;
255 } 285 }
256 InformSavePageDone(callback, result); 286 InformSavePageDone(callback, result);
257 DeletePendingArchiver(archiver); 287 DeletePendingArchiver(archiver);
288
289 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
258 } 290 }
259 291
260 void OfflinePageModel::OnUpdateOfflinePageDone( 292 void OfflinePageModel::OnMarkPageAccesseDone(
261 const OfflinePageItem& offline_page_item, bool success) { 293 const OfflinePageItem& offline_page_item, bool success) {
262 // Update the item in the cache only upon success. 294 // Update the item in the cache only upon success.
263 if (success) 295 if (success)
264 offline_pages_[offline_page_item.bookmark_id] = offline_page_item; 296 offline_pages_[offline_page_item.bookmark_id] = offline_page_item;
297
298 // No need to fire OfflinePageModelChanged event since updating access info
299 // should not have any impact to the UI.
300 }
301
302 void OfflinePageModel::OnMarkPageForDeletionDone(
303 const OfflinePageItem& offline_page_item,
304 const DeletePageCallback& callback,
305 bool success) {
306 // Update the item in the cache only upon success.
307 if (success)
308 offline_pages_[offline_page_item.bookmark_id] = offline_page_item;
309
310 InformDeletePageDone(callback, success ? DeletePageResult::SUCCESS
311 : DeletePageResult::STORE_FAILURE);
312
313 if (!success)
314 return;
315
316 // Schedule to do the final deletion.
317 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
318 FROM_HERE,
319 base::Bind(&OfflinePageModel::FinalizePageDeletion,
320 weak_ptr_factory_.GetWeakPtr()),
321 kFinalDeletionDelay);
322
323 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
324 }
325
326 void OfflinePageModel::OnUndoOfflinePageDone(
327 const OfflinePageItem& offline_page, bool success) {
328 if (!success)
329 return;
330 offline_pages_[offline_page.bookmark_id] = offline_page;
331
332 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
333 }
334
335 void OfflinePageModel::FinalizePageDeletion() {
336 std::vector<int64> bookmark_ids_pending_deletion;
337 for (const auto& id_page_pair : offline_pages_) {
338 if (!id_page_pair.second.IsMarkedForDeletion())
339 continue;
340 bookmark_ids_pending_deletion.push_back(id_page_pair.second.bookmark_id);
341 }
342 DeletePagesByBookmarkId(bookmark_ids_pending_deletion, DeletePageCallback());
343 }
344
345 void OfflinePageModel::UndoPageDeletion(int64 bookmark_id) {
346 auto iter = offline_pages_.find(bookmark_id);
347 if (iter == offline_pages_.end())
348 return;
349
350 // Make a copy of the cached item and update it. The cached item should only
351 // be updated upon the successful store operation.
352 OfflinePageItem offline_page_item = iter->second;
353 if (!offline_page_item.IsMarkedForDeletion())
354 return;
355
356 // Clear the flag to bring it back.
357 offline_page_item.ClearMarkForDeletion();
358 store_->AddOrUpdateOfflinePage(
359 offline_page_item,
360 base::Bind(&OfflinePageModel::OnUndoOfflinePageDone,
361 weak_ptr_factory_.GetWeakPtr(), offline_page_item));
265 } 362 }
266 363
267 void OfflinePageModel::BookmarkModelChanged() { 364 void OfflinePageModel::BookmarkModelChanged() {
268 } 365 }
269 366
367 void OfflinePageModel::BookmarkNodeAdded(bookmarks::BookmarkModel* model,
368 const bookmarks::BookmarkNode* parent,
369 int index) {
370 const bookmarks::BookmarkNode* node = parent->GetChild(index);
371 DCHECK(node);
372 UndoPageDeletion(node->id());
373 }
374
270 void OfflinePageModel::BookmarkNodeRemoved( 375 void OfflinePageModel::BookmarkNodeRemoved(
271 bookmarks::BookmarkModel* model, 376 bookmarks::BookmarkModel* model,
272 const bookmarks::BookmarkNode* parent, 377 const bookmarks::BookmarkNode* parent,
273 int old_index, 378 int old_index,
274 const bookmarks::BookmarkNode* node, 379 const bookmarks::BookmarkNode* node,
275 const std::set<GURL>& removed_urls) { 380 const std::set<GURL>& removed_urls) {
276 if (!is_loaded_) { 381 if (!is_loaded_) {
277 delayed_tasks_.push_back( 382 delayed_tasks_.push_back(
278 base::Bind(&OfflinePageModel::DeletePageByBookmarkId, 383 base::Bind(&OfflinePageModel::MarkPageForDeletion,
279 weak_ptr_factory_.GetWeakPtr(), 384 weak_ptr_factory_.GetWeakPtr(),
280 node->id(), 385 node->id(),
281 base::Bind(&EmptyDeleteCallback))); 386 base::Bind(&EmptyDeleteCallback)));
282 return; 387 return;
283 } 388 }
284 DeletePageByBookmarkId(node->id(), base::Bind(&EmptyDeleteCallback)); 389 MarkPageForDeletion(node->id(), base::Bind(&EmptyDeleteCallback));
285 } 390 }
286 391
287 void OfflinePageModel::OnLoadDone( 392 void OfflinePageModel::OnLoadDone(
288 bool success, 393 bool success,
289 const std::vector<OfflinePageItem>& offline_pages) { 394 const std::vector<OfflinePageItem>& offline_pages) {
290 DCHECK(!is_loaded_); 395 DCHECK(!is_loaded_);
291 is_loaded_ = true; 396 is_loaded_ = true;
292 397
293 if (success) { 398 if (success) {
294 for (const auto& offline_page : offline_pages) 399 for (const auto& offline_page : offline_pages)
295 offline_pages_[offline_page.bookmark_id] = offline_page; 400 offline_pages_[offline_page.bookmark_id] = offline_page;
296 } 401 }
297 402
298 // Run all the delayed tasks. 403 // Run all the delayed tasks.
299 for (const auto& delayed_task : delayed_tasks_) 404 for (const auto& delayed_task : delayed_tasks_)
300 delayed_task.Run(); 405 delayed_task.Run();
301 delayed_tasks_.clear(); 406 delayed_tasks_.clear();
302 407
408 // If there are pages that are marked for deletion, but not yet deleted and
409 // OfflinePageModel gets reloaded. Delete the pages now.
410 FinalizePageDeletion();
411
303 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelLoaded(this)); 412 FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelLoaded(this));
304 } 413 }
305 414
306 void OfflinePageModel::InformSavePageDone(const SavePageCallback& callback, 415 void OfflinePageModel::InformSavePageDone(const SavePageCallback& callback,
307 SavePageResult result) { 416 SavePageResult result) {
308 UMA_HISTOGRAM_ENUMERATION( 417 UMA_HISTOGRAM_ENUMERATION(
309 "OfflinePages.SavePageResult", 418 "OfflinePages.SavePageResult",
310 static_cast<int>(result), 419 static_cast<int>(result),
311 static_cast<int>(SavePageResult::RESULT_COUNT)); 420 static_cast<int>(SavePageResult::RESULT_COUNT));
312 callback.Run(result); 421 callback.Run(result);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 (success || bookmark_ids.size() > 1) ? DeletePageResult::SUCCESS 467 (success || bookmark_ids.size() > 1) ? DeletePageResult::SUCCESS
359 : DeletePageResult::STORE_FAILURE); 468 : DeletePageResult::STORE_FAILURE);
360 } 469 }
361 470
362 void OfflinePageModel::InformDeletePageDone(const DeletePageCallback& callback, 471 void OfflinePageModel::InformDeletePageDone(const DeletePageCallback& callback,
363 DeletePageResult result) { 472 DeletePageResult result) {
364 UMA_HISTOGRAM_ENUMERATION( 473 UMA_HISTOGRAM_ENUMERATION(
365 "OfflinePages.DeletePageResult", 474 "OfflinePages.DeletePageResult",
366 static_cast<int>(result), 475 static_cast<int>(result),
367 static_cast<int>(DeletePageResult::RESULT_COUNT)); 476 static_cast<int>(DeletePageResult::RESULT_COUNT));
368 callback.Run(result); 477 if (!callback.is_null())
478 callback.Run(result);
369 } 479 }
370 480
371 } // namespace offline_pages 481 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698