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

Side by Side Diff: components/offline_pages/background/pick_request_task.cc

Issue 2543093002: Split the RequestPicker task into two separate tasks. (Closed)
Patch Set: Created 4 years 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/background/pick_request_task.h" 5 #include "components/offline_pages/background/pick_request_task.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/time/time.h" 9 #include "base/time/time.h"
10 #include "components/offline_pages/background/device_conditions.h" 10 #include "components/offline_pages/background/device_conditions.h"
11 #include "components/offline_pages/background/offliner_policy.h" 11 #include "components/offline_pages/background/offliner_policy.h"
12 #include "components/offline_pages/background/request_coordinator_event_logger.h " 12 #include "components/offline_pages/background/request_coordinator_event_logger.h "
13 #include "components/offline_pages/background/request_notifier.h" 13 #include "components/offline_pages/background/request_notifier.h"
14 #include "components/offline_pages/background/request_queue_store.h" 14 #include "components/offline_pages/background/request_queue_store.h"
15 #include "components/offline_pages/background/save_page_request.h" 15 #include "components/offline_pages/background/save_page_request.h"
16 16
17 namespace { 17 namespace {
18 template <typename T> 18 template <typename T>
19 int signum(T t) { 19 int signum(T t) {
20 return (T(0) < t) - (t < T(0)); 20 return (T(0) < t) - (t < T(0));
21 } 21 }
22 22
23 #define CALL_MEMBER_FUNCTION(object, ptrToMember) ((object)->*(ptrToMember)) 23 #define CALL_MEMBER_FUNCTION(object, ptrToMember) ((object)->*(ptrToMember))
24 } // namespace 24 } // namespace
25 25
26 namespace offline_pages { 26 namespace offline_pages {
27 27
28 PickRequestTask::PickRequestTask(RequestQueueStore* store, 28 PickRequestTask::PickRequestTask(RequestQueueStore* store,
29 OfflinerPolicy* policy, 29 OfflinerPolicy* policy,
30 RequestNotifier* notifier,
31 RequestCoordinatorEventLogger* event_logger,
32 RequestPickedCallback picked_callback, 30 RequestPickedCallback picked_callback,
33 RequestNotPickedCallback not_picked_callback, 31 RequestNotPickedCallback not_picked_callback,
34 RequestCountCallback request_count_callback, 32 RequestCountCallback request_count_callback,
35 DeviceConditions& device_conditions, 33 DeviceConditions& device_conditions,
36 const std::set<int64_t>& disabled_requests) 34 const std::set<int64_t>& disabled_requests)
37 : store_(store), 35 : store_(store),
38 policy_(policy), 36 policy_(policy),
39 notifier_(notifier),
40 event_logger_(event_logger),
41 picked_callback_(picked_callback), 37 picked_callback_(picked_callback),
42 not_picked_callback_(not_picked_callback), 38 not_picked_callback_(not_picked_callback),
43 request_count_callback_(request_count_callback), 39 request_count_callback_(request_count_callback),
44 disabled_requests_(disabled_requests), 40 disabled_requests_(disabled_requests),
45 weak_ptr_factory_(this) { 41 weak_ptr_factory_(this) {
46 device_conditions_.reset(new DeviceConditions(device_conditions)); 42 device_conditions_.reset(new DeviceConditions(device_conditions));
47 } 43 }
48 44
49 PickRequestTask::~PickRequestTask() {} 45 PickRequestTask::~PickRequestTask() {}
50 46
51 void PickRequestTask::Run() { 47 void PickRequestTask::Run() {
52 // Get all the requests from the queue, we will classify them in the callback. 48 GetRequests();
53 store_->GetRequests(base::Bind(&PickRequestTask::ChooseAndPrune,
54 weak_ptr_factory_.GetWeakPtr()));
55 } 49 }
56 50
57 void PickRequestTask::ChooseAndPrune( 51 void PickRequestTask::GetRequests() {
52 // Get all the requests from the queue, we will classify them in the callback.
53 store_->GetRequests(
54 base::Bind(&PickRequestTask::Choose, weak_ptr_factory_.GetWeakPtr()));
55 }
56
57 void PickRequestTask::Choose(
58 bool success, 58 bool success,
59 std::vector<std::unique_ptr<SavePageRequest>> requests) { 59 std::vector<std::unique_ptr<SavePageRequest>> requests) {
60 // If there is nothing to do, return right away. 60 // If there is nothing to do, return right away.
61 if (requests.empty()) { 61 if (requests.empty()) {
62 request_count_callback_.Run(requests.size(), 0); 62 request_count_callback_.Run(requests.size(), 0);
63 not_picked_callback_.Run(false); 63 not_picked_callback_.Run(false, false);
dougarnett 2016/12/02 17:20:27 ...(false /* non user requests */, false /* cleanu
Pete Williamson 2016/12/05 20:39:45 I did this, but with enums, not comments, WDYT?
dougarnett 2016/12/05 21:27:45 The constants are fine. I have noticed the parm co
Pete Williamson 2016/12/06 00:25:38 I've always preferred named constants to comments.
64 TaskComplete(); 64 TaskComplete();
65 return; 65 return;
66 } 66 }
67 67
68 // Get the expired requests to be removed from the queue, and the valid ones
69 // from which to pick the next request.
70 std::vector<std::unique_ptr<SavePageRequest>> valid_requests;
71 std::vector<int64_t> expired_request_ids;
72 SplitRequests(std::move(requests), &valid_requests, &expired_request_ids);
73
74 // Continue processing by choosing a request.
75 ChooseRequestAndCallback(std::move(valid_requests));
76
77 // Continue processing by handling expired requests, if any.
78 if (expired_request_ids.size() == 0) {
79 TaskComplete();
80 return;
81 }
82
83 RemoveStaleRequests(std::move(expired_request_ids));
84 }
85
86 void PickRequestTask::ChooseRequestAndCallback(
87 std::vector<std::unique_ptr<SavePageRequest>> valid_requests) {
88 // Pick the most deserving request for our conditions. 68 // Pick the most deserving request for our conditions.
89 const SavePageRequest* picked_request = nullptr; 69 const SavePageRequest* picked_request = nullptr;
90 70
91 RequestCompareFunction comparator = nullptr; 71 RequestCompareFunction comparator = nullptr;
92 72
93 // Choose which comparison function to use based on policy. 73 // Choose which comparison function to use based on policy.
94 if (policy_->RetryCountIsMoreImportantThanRecency()) 74 if (policy_->RetryCountIsMoreImportantThanRecency())
95 comparator = &PickRequestTask::RetryCountFirstCompareFunction; 75 comparator = &PickRequestTask::RetryCountFirstCompareFunction;
96 else 76 else
97 comparator = &PickRequestTask::RecencyFirstCompareFunction; 77 comparator = &PickRequestTask::RecencyFirstCompareFunction;
98 78
99 // TODO(petewil): Consider replacing this bool with a better named enum. 79 // TODO(petewil): Consider replacing this bool with a better named enum.
100 bool non_user_requested_tasks_remaining = false; 80 bool non_user_requested_tasks_remaining = false;
81 bool cleanup_needed = false;
101 82
102 size_t available_request_count = 0; 83 size_t available_request_count = 0;
103 84
104 // Iterate once through the requests, keeping track of best candidate. 85 // Iterate once through the requests, keeping track of best candidate.
105 for (unsigned i = 0; i < valid_requests.size(); ++i) { 86 for (unsigned i = 0; i < requests.size(); ++i) {
87 // If the request is expired or has exceeded the retry count, skip it.
88 if (base::Time::Now() - requests[i]->creation_time() >=
fgorski 2016/12/02 21:44:04 One more reason to extract a method as suggested e
Pete Williamson 2016/12/05 20:39:45 Done, new class is OfflinerPolicyUtils.
89 base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds) ||
90 requests[i]->started_attempt_count() >= policy_->GetMaxStartedTries() ||
91 requests[i]->completed_attempt_count() >=
92 policy_->GetMaxCompletedTries()) {
93 cleanup_needed = true;
94 continue;
95 }
96
106 // If the request is on the disabled list, skip it. 97 // If the request is on the disabled list, skip it.
107 auto search = disabled_requests_.find(valid_requests[i]->request_id()); 98 auto search = disabled_requests_.find(requests[i]->request_id());
108 if (search != disabled_requests_.end()) 99 if (search != disabled_requests_.end())
109 continue; 100 continue;
101
110 // If there are non-user-requested tasks remaining, we need to make sure 102 // If there are non-user-requested tasks remaining, we need to make sure
111 // that they are scheduled after we run out of user requested tasks. Here we 103 // that they are scheduled after we run out of user requested tasks. Here we
112 // detect if any exist. If we don't find any user-requested tasks, we will 104 // detect if any exist. If we don't find any user-requested tasks, we will
113 // inform the "not_picked_callback_" that it needs to schedule a task for 105 // inform the "not_picked_callback_" that it needs to schedule a task for
114 // non-user-requested items, which have different network and power needs. 106 // non-user-requested items, which have different network and power needs.
115 if (!valid_requests[i]->user_requested()) 107 if (!requests[i]->user_requested())
116 non_user_requested_tasks_remaining = true; 108 non_user_requested_tasks_remaining = true;
117 if (valid_requests[i]->request_state() == 109 if (requests[i]->request_state() ==
118 SavePageRequest::RequestState::AVAILABLE) { 110 SavePageRequest::RequestState::AVAILABLE) {
119 available_request_count++; 111 available_request_count++;
120 } 112 }
121 if (!RequestConditionsSatisfied(valid_requests[i].get())) 113 if (!RequestConditionsSatisfied(requests[i].get()))
122 continue; 114 continue;
123 if (IsNewRequestBetter(picked_request, valid_requests[i].get(), comparator)) 115 if (IsNewRequestBetter(picked_request, requests[i].get(), comparator))
124 picked_request = valid_requests[i].get(); 116 picked_request = requests[i].get();
125 } 117 }
126 118
127 // Report the request queue counts. 119 // Report the request queue counts. TODO(reviewers): This used to report only
128 request_count_callback_.Run(valid_requests.size(), available_request_count); 120 // the count of valid entries, but now we report all entries. Reviewers, is
dougarnett 2016/12/02 23:00:11 Looks fine. Before valid_requests.size() was the t
Pete Williamson 2016/12/05 20:39:45 Acknowledged.
121 // that a problem?
122 request_count_callback_.Run(requests.size(), available_request_count);
129 123
130 // If we have a best request to try next, get the request coodinator to 124 // If we have a best request to try next, get the request coodinator to
131 // start it. Otherwise return that we have no candidates. 125 // start it. Otherwise return that we have no candidates.
132 if (picked_request != nullptr) 126 if (picked_request != nullptr)
fgorski 2016/12/02 21:44:04 add {} to both clauses, because your else spans mu
Pete Williamson 2016/12/05 20:39:45 Ah, I must have missed seeing it wrap. Fixed.
133 picked_callback_.Run(*picked_request); 127 picked_callback_.Run(*picked_request, cleanup_needed);
134 else 128 else
135 not_picked_callback_.Run(non_user_requested_tasks_remaining); 129 not_picked_callback_.Run(non_user_requested_tasks_remaining,
136 } 130 cleanup_needed);
137 131
138 // Continue the async part of the processing by deleting the expired requests.
139 // TODO(petewil): Does that really need to be done on the task queue? Hard to
140 // see how we need to wait for it before starting the next task. OTOH, we'd hate
141 // to do a second slow DB operation to get entries a second time, and waiting
142 // until this is done will make sure other gets don't see these old entries.
143 // Consider moving this to a fresh task type to clean the queue.
144 void PickRequestTask::RemoveStaleRequests(
145 std::vector<int64_t> stale_request_ids) {
146 store_->RemoveRequests(stale_request_ids,
147 base::Bind(&PickRequestTask::OnRequestsExpired,
148 weak_ptr_factory_.GetWeakPtr()));
149 }
150
151 void PickRequestTask::OnRequestsExpired(
152 std::unique_ptr<UpdateRequestsResult> result) {
153 RequestNotifier::BackgroundSavePageResult save_page_result(
154 RequestNotifier::BackgroundSavePageResult::EXPIRED);
155 for (const auto& request : result->updated_items) {
156 event_logger_->RecordDroppedSavePageRequest(
157 request.client_id().name_space, save_page_result, request.request_id());
158 notifier_->NotifyCompleted(request, save_page_result);
159 }
160
161 // The task is now done, return control to the task queue.
162 TaskComplete(); 132 TaskComplete();
163 } 133 }
164 134
165 void PickRequestTask::SplitRequests(
166 std::vector<std::unique_ptr<SavePageRequest>> requests,
167 std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
168 std::vector<int64_t>* expired_request_ids) {
169 for (auto& request : requests) {
170 if (base::Time::Now() - request->creation_time() >=
171 base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds)) {
172 expired_request_ids->push_back(request->request_id());
173 } else {
174 valid_requests->push_back(std::move(request));
175 }
176 }
177 }
178
179 // Filter out requests that don't meet the current conditions. For instance, if 135 // Filter out requests that don't meet the current conditions. For instance, if
180 // this is a predictive request, and we are not on WiFi, it should be ignored 136 // this is a predictive request, and we are not on WiFi, it should be ignored
181 // this round. 137 // this round.
182 bool PickRequestTask::RequestConditionsSatisfied( 138 bool PickRequestTask::RequestConditionsSatisfied(
183 const SavePageRequest* request) { 139 const SavePageRequest* request) {
184 // If the user did not request the page directly, make sure we are connected 140 // If the user did not request the page directly, make sure we are connected
185 // to power and have WiFi and sufficient battery remaining before we take this 141 // to power and have WiFi and sufficient battery remaining before we take this
186 // request. 142 // request.
187 if (!device_conditions_->IsPowerConnected() && 143 if (!device_conditions_->IsPowerConnected() &&
188 policy_->PowerRequired(request->user_requested())) { 144 policy_->PowerRequired(request->user_requested())) {
189 return false; 145 return false;
190 } 146 }
191 147
192 if (device_conditions_->GetNetConnectionType() != 148 if (device_conditions_->GetNetConnectionType() !=
193 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI && 149 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI &&
194 policy_->UnmeteredNetworkRequired(request->user_requested())) { 150 policy_->UnmeteredNetworkRequired(request->user_requested())) {
195 return false; 151 return false;
196 } 152 }
197 153
198 if (device_conditions_->GetBatteryPercentage() < 154 if (device_conditions_->GetBatteryPercentage() <
199 policy_->BatteryPercentageRequired(request->user_requested())) { 155 policy_->BatteryPercentageRequired(request->user_requested())) {
200 return false; 156 return false;
201 } 157 }
202 158
203 // If we have already started this page the max number of times, it is not
204 // eligible to try again.
205 if (request->started_attempt_count() >= policy_->GetMaxStartedTries())
206 return false;
207
208 // If we have already completed trying this page the max number of times, it
209 // is not eligible to try again.
210 if (request->completed_attempt_count() >= policy_->GetMaxCompletedTries())
211 return false;
212
213 // If the request is paused, do not consider it. 159 // If the request is paused, do not consider it.
214 if (request->request_state() == SavePageRequest::RequestState::PAUSED) 160 if (request->request_state() == SavePageRequest::RequestState::PAUSED)
215 return false; 161 return false;
216 162
217 // If the request is expired, do not consider it.
218 base::TimeDelta requestAge = base::Time::Now() - request->creation_time();
219 if (requestAge > base::TimeDelta::FromSeconds(
220 policy_->GetRequestExpirationTimeInSeconds()))
221 return false;
222
223 // If this request is not active yet, return false. 163 // If this request is not active yet, return false.
224 // TODO(petewil): If the only reason we return nothing to do is that we have 164 // TODO(petewil): If the only reason we return nothing to do is that we have
225 // inactive requests, we still want to try again later after their activation 165 // inactive requests, we still want to try again later after their activation
226 // time elapses, we shouldn't take ourselves completely off the scheduler. 166 // time elapses, we shouldn't take ourselves completely off the scheduler.
227 if (request->activation_time() > base::Time::Now()) 167 if (request->activation_time() > base::Time::Now())
228 return false; 168 return false;
229 169
230 return true; 170 return true;
231 } 171 }
232 172
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 int result = signum(difference.InMilliseconds()); 245 int result = signum(difference.InMilliseconds());
306 246
307 // Flip the direction of comparison if policy prefers fewer retries. 247 // Flip the direction of comparison if policy prefers fewer retries.
308 if (policy_->ShouldPreferEarlierRequests()) 248 if (policy_->ShouldPreferEarlierRequests())
309 result *= -1; 249 result *= -1;
310 250
311 return result; 251 return result;
312 } 252 }
313 253
314 } // namespace offline_pages 254 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698