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

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

Issue 2006923005: [Offline Pages] Two-step expiration in storage manager. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: more comments, commit ready. Created 4 years, 7 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 2016 The Chromium Authors. All rights reserved. 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 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_storage_manager.h" 5 #include "components/offline_pages/offline_page_storage_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/time/clock.h" 10 #include "base/time/clock.h"
11 #include "base/time/default_clock.h" 11 #include "base/time/default_clock.h"
12 #include "components/offline_pages/client_policy_controller.h" 12 #include "components/offline_pages/client_policy_controller.h"
13 #include "components/offline_pages/offline_page_client_policy.h" 13 #include "components/offline_pages/offline_page_client_policy.h"
14 #include "components/offline_pages/offline_page_item.h" 14 #include "components/offline_pages/offline_page_item.h"
15 15
16 namespace offline_pages { 16 namespace offline_pages {
17 17
18 OfflinePageStorageManager::OfflinePageStorageManager( 18 OfflinePageStorageManager::OfflinePageStorageManager(
19 Client* client, 19 Client* client,
20 ClientPolicyController* policy_controller, 20 ClientPolicyController* policy_controller,
21 ArchiveManager* archive_manager) 21 ArchiveManager* archive_manager)
22 : client_(client), 22 : client_(client),
23 policy_controller_(policy_controller), 23 policy_controller_(policy_controller),
24 archive_manager_(archive_manager), 24 archive_manager_(archive_manager),
25 in_progress_(false),
26 clock_(new base::DefaultClock()), 25 clock_(new base::DefaultClock()),
27 weak_ptr_factory_(this) {} 26 weak_ptr_factory_(this) {}
28 27
29 OfflinePageStorageManager::~OfflinePageStorageManager() {} 28 OfflinePageStorageManager::~OfflinePageStorageManager() {}
30 29
31 void OfflinePageStorageManager::ClearPagesIfNeeded( 30 void OfflinePageStorageManager::ClearPagesIfNeeded(
32 const ClearPagesCallback& callback) { 31 const ClearPagesCallback& callback) {
33 if (in_progress_) 32 if (IsInProgress())
34 return; 33 return;
35 in_progress_ = true; 34 clear_time_ = clock_->Now();
36 archive_manager_->GetStorageStats( 35 archive_manager_->GetStorageStats(base::Bind(
37 base::Bind(&OfflinePageStorageManager::OnGetStorageStatsDone, 36 &OfflinePageStorageManager::OnGetStorageStatsDoneForClearingPages,
38 weak_ptr_factory_.GetWeakPtr(), callback)); 37 weak_ptr_factory_.GetWeakPtr(), callback));
39 } 38 }
40 39
41 void OfflinePageStorageManager::SetClockForTesting( 40 void OfflinePageStorageManager::SetClockForTesting(
42 std::unique_ptr<base::Clock> clock) { 41 std::unique_ptr<base::Clock> clock) {
43 clock_ = std::move(clock); 42 clock_ = std::move(clock);
44 } 43 }
45 44
46 void OfflinePageStorageManager::OnGetStorageStatsDone( 45 void OfflinePageStorageManager::OnGetStorageStatsDoneForClearingPages(
47 const ClearPagesCallback& callback, 46 const ClearPagesCallback& callback,
48 const ArchiveManager::StorageStats& stats) { 47 const ArchiveManager::StorageStats& stats) {
49 DCHECK(in_progress_); 48 DCHECK(IsInProgress());
50 ClearMode mode = ShouldClearPages(stats); 49 ClearMode mode = ShouldClearPages(stats);
51 if (mode == ClearMode::NOT_NEEDED) { 50 if (mode == ClearMode::NOT_NEEDED) {
52 in_progress_ = false; 51 last_clear_time_ = clear_time_;
53 last_clear_time_ = clock_->Now();
54 callback.Run(0, ClearStorageResult::UNNECESSARY); 52 callback.Run(0, ClearStorageResult::UNNECESSARY);
55 return; 53 return;
56 } 54 }
57 client_->GetAllPages(base::Bind(&OfflinePageStorageManager::OnGetAllPagesDone, 55 client_->GetAllPages(
58 weak_ptr_factory_.GetWeakPtr(), callback, 56 base::Bind(&OfflinePageStorageManager::OnGetAllPagesDoneForClearingPages,
59 stats)); 57 weak_ptr_factory_.GetWeakPtr(), callback, stats));
60 } 58 }
61 59
62 void OfflinePageStorageManager::OnGetAllPagesDone( 60 void OfflinePageStorageManager::OnGetAllPagesDoneForClearingPages(
63 const ClearPagesCallback& callback, 61 const ClearPagesCallback& callback,
64 const ArchiveManager::StorageStats& stats, 62 const ArchiveManager::StorageStats& stats,
65 const MultipleOfflinePageItemResult& pages) { 63 const MultipleOfflinePageItemResult& pages) {
66 std::vector<int64_t> offline_ids; 64 std::vector<int64_t> page_ids_to_expire;
67 GetExpiredPageIds(pages, stats, offline_ids); 65 std::vector<int64_t> page_ids_to_remove;
68 client_->DeletePagesByOfflineId( 66 GetPageIdsToClear(pages, stats, &page_ids_to_expire, &page_ids_to_remove);
69 offline_ids, base::Bind(&OfflinePageStorageManager::OnExpiredPagesDeleted, 67 client_->ExpirePages(
70 weak_ptr_factory_.GetWeakPtr(), callback, 68 page_ids_to_expire, clear_time_,
71 static_cast<int>(offline_ids.size()))); 69 base::Bind(&OfflinePageStorageManager::OnPagesExpired,
70 weak_ptr_factory_.GetWeakPtr(), callback,
71 page_ids_to_expire.size(), page_ids_to_remove));
72 } 72 }
73 73
74 void OfflinePageStorageManager::OnExpiredPagesDeleted( 74 void OfflinePageStorageManager::OnPagesExpired(
75 const ClearPagesCallback& callback, 75 const ClearPagesCallback& callback,
76 int pages_cleared, 76 size_t pages_expired,
77 const std::vector<int64_t>& page_ids_to_remove,
78 bool expiration_succeeded) {
79 // We want to delete the outdated page records regardless the expiration
80 // succeeded or not.
81 client_->DeletePagesByOfflineId(
82 page_ids_to_remove,
83 base::Bind(&OfflinePageStorageManager::OnOutdatedPagesCleared,
84 weak_ptr_factory_.GetWeakPtr(), callback, pages_expired,
85 expiration_succeeded));
86 }
87
88 void OfflinePageStorageManager::OnOutdatedPagesCleared(
89 const ClearPagesCallback& callback,
90 size_t pages_cleared,
91 bool expiration_succeeded,
77 DeletePageResult result) { 92 DeletePageResult result) {
78 last_clear_time_ = clock_->Now(); 93 ClearStorageResult clear_result = ClearStorageResult::SUCCESS;
79 ClearStorageResult clear_result = result == DeletePageResult::SUCCESS 94 if (!expiration_succeeded) {
80 ? ClearStorageResult::SUCCESS 95 clear_result = ClearStorageResult::EXPIRE_FAILURE;
81 : ClearStorageResult::DELETE_FAILURE; 96 if (result != DeletePageResult::SUCCESS)
82 in_progress_ = false; 97 clear_result = ClearStorageResult::EXPIRE_AND_DELETE_FAILURES;
98 } else if (result != DeletePageResult::SUCCESS) {
99 clear_result = ClearStorageResult::DELETE_FAILURE;
100 }
101 last_clear_time_ = clear_time_;
83 callback.Run(pages_cleared, clear_result); 102 callback.Run(pages_cleared, clear_result);
84 } 103 }
85 104
86 void OfflinePageStorageManager::GetExpiredPageIds( 105 void OfflinePageStorageManager::GetPageIdsToClear(
87 const MultipleOfflinePageItemResult& pages, 106 const MultipleOfflinePageItemResult& pages,
88 const ArchiveManager::StorageStats& stats, 107 const ArchiveManager::StorageStats& stats,
89 std::vector<int64_t>& offline_ids) { 108 std::vector<int64_t>* page_ids_to_expire,
90 base::Time now = clock_->Now(); 109 std::vector<int64_t>* page_ids_to_remove) {
91
92 // Creating a map from namespace to a vector of page items. 110 // Creating a map from namespace to a vector of page items.
93 // Sort each vector based on last accessed time and all pages after index 111 // Sort each vector based on last accessed time and all pages after index
94 // min{size(), page_limit} should be expired. And then start iterating 112 // min{size(), page_limit} should be expired. And then start iterating
95 // backwards to expire pages. 113 // backwards to expire pages.
96 std::map<std::string, std::vector<OfflinePageItem>> pages_map; 114 std::map<std::string, std::vector<OfflinePageItem>> pages_map;
97 std::vector<OfflinePageItem> kept_pages; 115 std::vector<OfflinePageItem> kept_pages;
98 int64_t kept_pages_size = 0; 116 int64_t kept_pages_size = 0;
99 117
100 for (const auto& page : pages) 118 for (const auto& page : pages) {
101 pages_map[page.client_id.name_space].push_back(page); 119 if (!page.IsExpired()) {
120 pages_map[page.client_id.name_space].push_back(page);
121 } else if (clear_time_ - page.expiration_time >= kRemovePageItemInterval) {
122 page_ids_to_remove->push_back(page.offline_id);
123 }
124 }
102 125
103 for (auto& iter : pages_map) { 126 for (auto& iter : pages_map) {
104 std::string name_space = iter.first; 127 std::string name_space = iter.first;
105 std::vector<OfflinePageItem>& page_list = iter.second; 128 std::vector<OfflinePageItem>& page_list = iter.second;
106 129
107 LifetimePolicy policy = 130 LifetimePolicy policy =
108 policy_controller_->GetPolicy(name_space).lifetime_policy; 131 policy_controller_->GetPolicy(name_space).lifetime_policy;
109 132
110 std::sort(page_list.begin(), page_list.end(), 133 std::sort(page_list.begin(), page_list.end(),
111 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool { 134 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool {
112 return a.last_access_time > b.last_access_time; 135 return a.last_access_time > b.last_access_time;
113 }); 136 });
114 137
115 int page_list_size = static_cast<int>(page_list.size()); 138 size_t page_list_size = page_list.size();
116 int pos = 0; 139 size_t pos = 0;
117 while (pos < page_list_size && 140 while (pos < page_list_size &&
118 (policy.page_limit == kUnlimitedPages || pos < policy.page_limit) && 141 (policy.page_limit == kUnlimitedPages || pos < policy.page_limit) &&
119 !ShouldBeExpired(now, page_list.at(pos))) { 142 !ShouldBeExpired(page_list.at(pos))) {
120 kept_pages_size += page_list.at(pos).file_size; 143 kept_pages_size += page_list.at(pos).file_size;
121 kept_pages.push_back(page_list.at(pos)); 144 kept_pages.push_back(page_list.at(pos));
122 pos++; 145 pos++;
123 } 146 }
124 147
125 for (; pos < page_list_size; pos++) 148 for (; pos < page_list_size; pos++)
126 offline_ids.push_back(page_list.at(pos).offline_id); 149 page_ids_to_expire->push_back(page_list.at(pos).offline_id);
127 } 150 }
128 151
129 // If we're still over the clear threshold, we're going to clear remaining 152 // If we're still over the clear threshold, we're going to clear remaining
130 // pages from oldest last access time. 153 // pages from oldest last access time.
131 int64_t free_space = stats.free_disk_space; 154 int64_t free_space = stats.free_disk_space;
132 int64_t total_size = stats.total_archives_size; 155 int64_t total_size = stats.total_archives_size;
133 int64_t space_to_release = 156 int64_t space_to_release =
134 kept_pages_size - 157 kept_pages_size -
135 (total_size + free_space) * kOfflinePageStorageClearThreshold; 158 (total_size + free_space) * kOfflinePageStorageClearThreshold;
136 if (space_to_release > 0) { 159 if (space_to_release > 0) {
137 // Here we're sorting the |kept_pages| with oldest first. 160 // Here we're sorting the |kept_pages| with oldest first.
138 std::sort(kept_pages.begin(), kept_pages.end(), 161 std::sort(kept_pages.begin(), kept_pages.end(),
139 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool { 162 [](const OfflinePageItem& a, const OfflinePageItem& b) -> bool {
140 return a.last_access_time < b.last_access_time; 163 return a.last_access_time < b.last_access_time;
141 }); 164 });
142 int kept_pages_size = static_cast<int>(kept_pages.size()); 165 size_t kept_pages_size = kept_pages.size();
143 int pos = 0; 166 size_t pos = 0;
144 while (pos < kept_pages_size && space_to_release > 0) { 167 while (pos < kept_pages_size && space_to_release > 0) {
145 space_to_release -= kept_pages.at(pos).file_size; 168 space_to_release -= kept_pages.at(pos).file_size;
146 offline_ids.push_back(kept_pages.at(pos).offline_id); 169 page_ids_to_expire->push_back(kept_pages.at(pos).offline_id);
147 pos++; 170 pos++;
148 } 171 }
149 } 172 }
150 } 173 }
151 174
152 OfflinePageStorageManager::ClearMode 175 OfflinePageStorageManager::ClearMode
153 OfflinePageStorageManager::ShouldClearPages( 176 OfflinePageStorageManager::ShouldClearPages(
154 const ArchiveManager::StorageStats& storage_stats) { 177 const ArchiveManager::StorageStats& storage_stats) {
155 int64_t total_size = storage_stats.total_archives_size; 178 int64_t total_size = storage_stats.total_archives_size;
156 int64_t free_space = storage_stats.free_disk_space; 179 int64_t free_space = storage_stats.free_disk_space;
157 if (total_size == 0) 180 if (total_size == 0)
158 return ClearMode::NOT_NEEDED; 181 return ClearMode::NOT_NEEDED;
159 182
160 // If the size of all offline pages is more than limit, or it's larger than a 183 // If the size of all offline pages is more than limit, or it's larger than a
161 // specified percentage of all available storage space on the disk we'll clear 184 // specified percentage of all available storage space on the disk we'll clear
162 // all offline pages. 185 // all offline pages.
163 if (total_size >= (total_size + free_space) * kOfflinePageStorageLimit) 186 if (total_size >= (total_size + free_space) * kOfflinePageStorageLimit)
164 return ClearMode::DEFAULT; 187 return ClearMode::DEFAULT;
165 // If it's been more than the pre-defined interval since the last time we 188 // If it's been more than the pre-defined interval since the last time we
166 // clear the storage, we should clear pages. 189 // clear the storage, we should clear pages.
167 if (last_clear_time_ == base::Time() || 190 if (last_clear_time_ == base::Time() ||
168 clock_->Now() - last_clear_time_ >= kClearStorageInterval) { 191 clear_time_ - last_clear_time_ >= kClearStorageInterval) {
169 return ClearMode::DEFAULT; 192 return ClearMode::DEFAULT;
170 } 193 }
171
172 // Otherwise there's no need to clear storage right now. 194 // Otherwise there's no need to clear storage right now.
173 return ClearMode::NOT_NEEDED; 195 return ClearMode::NOT_NEEDED;
174 } 196 }
175 197
176 bool OfflinePageStorageManager::ShouldBeExpired(const base::Time& now, 198 bool OfflinePageStorageManager::ShouldBeExpired(
177 const OfflinePageItem& page) { 199 const OfflinePageItem& page) const {
178 const LifetimePolicy& policy = 200 const LifetimePolicy& policy =
179 policy_controller_->GetPolicy(page.client_id.name_space).lifetime_policy; 201 policy_controller_->GetPolicy(page.client_id.name_space).lifetime_policy;
180 return now - page.last_access_time >= policy.expiration_period; 202 return clear_time_ - page.last_access_time >= policy.expiration_period;
203 }
204
205 bool OfflinePageStorageManager::IsInProgress() const {
206 return clear_time_ > last_clear_time_;
181 } 207 }
182 208
183 } // namespace offline_pages 209 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698