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

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

Issue 2489443002: Move all components/offline_pages/ files into component/offline_pages/core (Closed)
Patch Set: update Created 4 years, 1 month 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
(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/background/pick_request_task.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/time/time.h"
10 #include "components/offline_pages/background/device_conditions.h"
11 #include "components/offline_pages/background/offliner_policy.h"
12 #include "components/offline_pages/background/request_coordinator_event_logger.h "
13 #include "components/offline_pages/background/request_notifier.h"
14 #include "components/offline_pages/background/request_queue_store.h"
15 #include "components/offline_pages/background/save_page_request.h"
16
17 namespace {
18 template <typename T>
19 int signum(T t) {
20 return (T(0) < t) - (t < T(0));
21 }
22
23 #define CALL_MEMBER_FUNCTION(object, ptrToMember) ((object)->*(ptrToMember))
24 } // namespace
25
26 namespace offline_pages {
27
28 PickRequestTask::PickRequestTask(RequestQueueStore* store,
29 OfflinerPolicy* policy,
30 RequestNotifier* notifier,
31 RequestCoordinatorEventLogger* event_logger,
32 RequestPickedCallback picked_callback,
33 RequestNotPickedCallback not_picked_callback,
34 DeviceConditions& device_conditions,
35 const std::set<int64_t>& disabled_requests)
36 : store_(store),
37 policy_(policy),
38 notifier_(notifier),
39 event_logger_(event_logger),
40 picked_callback_(picked_callback),
41 not_picked_callback_(not_picked_callback),
42 disabled_requests_(disabled_requests),
43 weak_ptr_factory_(this) {
44 device_conditions_.reset(new DeviceConditions(device_conditions));
45 }
46
47 PickRequestTask::~PickRequestTask() {}
48
49 void PickRequestTask::Run() {
50 // Get all the requests from the queue, we will classify them in the callback.
51 store_->GetRequests(base::Bind(&PickRequestTask::ChooseAndPrune,
52 weak_ptr_factory_.GetWeakPtr()));
53 }
54
55 void PickRequestTask::ChooseAndPrune(
56 bool success,
57 std::vector<std::unique_ptr<SavePageRequest>> requests) {
58 // If there is nothing to do, return right away.
59 if (requests.size() == 0) {
60 not_picked_callback_.Run(false);
61 TaskComplete();
62 return;
63 }
64
65 // Get the expired requests to be removed from the queue, and the valid ones
66 // from which to pick the next request.
67 std::vector<std::unique_ptr<SavePageRequest>> valid_requests;
68 std::vector<int64_t> expired_request_ids;
69 SplitRequests(std::move(requests), &valid_requests, &expired_request_ids);
70
71 // Continue processing by choosing a request.
72 ChooseRequestAndCallback(std::move(valid_requests));
73
74 // Continue processing by handling expired requests, if any.
75 if (expired_request_ids.size() == 0) {
76 TaskComplete();
77 return;
78 }
79
80 RemoveStaleRequests(std::move(expired_request_ids));
81 }
82
83 void PickRequestTask::ChooseRequestAndCallback(
84 std::vector<std::unique_ptr<SavePageRequest>> valid_requests) {
85 // Pick the most deserving request for our conditions.
86 const SavePageRequest* picked_request = nullptr;
87
88 RequestCompareFunction comparator = nullptr;
89
90 // Choose which comparison function to use based on policy.
91 if (policy_->RetryCountIsMoreImportantThanRecency())
92 comparator = &PickRequestTask::RetryCountFirstCompareFunction;
93 else
94 comparator = &PickRequestTask::RecencyFirstCompareFunction;
95
96 // TODO(petewil): Consider replacing this bool with a better named enum.
97 bool non_user_requested_tasks_remaining = false;
98
99 // Iterate once through the requests, keeping track of best candidate.
100 for (unsigned i = 0; i < valid_requests.size(); ++i) {
101 // If the request is on the disabled list, skip it.
102 auto search = disabled_requests_.find(valid_requests[i]->request_id());
103 if (search != disabled_requests_.end())
104 continue;
105 // If there are non-user-requested tasks remaining, we need to make sure
106 // that they are scheduled after we run out of user requested tasks. Here we
107 // detect if any exist. If we don't find any user-requested tasks, we will
108 // inform the "not_picked_callback_" that it needs to schedule a task for
109 // non-user-requested items, which have different network and power needs.
110 if (!valid_requests[i]->user_requested())
111 non_user_requested_tasks_remaining = true;
112 if (!RequestConditionsSatisfied(valid_requests[i].get()))
113 continue;
114 if (IsNewRequestBetter(picked_request, valid_requests[i].get(), comparator))
115 picked_request = valid_requests[i].get();
116 }
117
118 // If we have a best request to try next, get the request coodinator to
119 // start it. Otherwise return that we have no candidates.
120 if (picked_request != nullptr)
121 picked_callback_.Run(*picked_request);
122 else
123 not_picked_callback_.Run(non_user_requested_tasks_remaining);
124 }
125
126 // Continue the async part of the processing by deleting the expired requests.
127 // TODO(petewil): Does that really need to be done on the task queue? Hard to
128 // see how we need to wait for it before starting the next task. OTOH, we'd hate
129 // to do a second slow DB operation to get entries a second time, and waiting
130 // until this is done will make sure other gets don't see these old entries.
131 // Consider moving this to a fresh task type to clean the queue.
132 void PickRequestTask::RemoveStaleRequests(
133 std::vector<int64_t> stale_request_ids) {
134 store_->RemoveRequests(stale_request_ids,
135 base::Bind(&PickRequestTask::OnRequestsExpired,
136 weak_ptr_factory_.GetWeakPtr()));
137 }
138
139 void PickRequestTask::OnRequestsExpired(
140 std::unique_ptr<UpdateRequestsResult> result) {
141 RequestNotifier::BackgroundSavePageResult save_page_result(
142 RequestNotifier::BackgroundSavePageResult::EXPIRED);
143 for (const auto& request : result->updated_items) {
144 event_logger_->RecordDroppedSavePageRequest(
145 request.client_id().name_space, save_page_result, request.request_id());
146 notifier_->NotifyCompleted(request, save_page_result);
147 }
148
149 // The task is now done, return control to the task queue.
150 TaskComplete();
151 }
152
153 void PickRequestTask::SplitRequests(
154 std::vector<std::unique_ptr<SavePageRequest>> requests,
155 std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
156 std::vector<int64_t>* expired_request_ids) {
157 for (auto& request : requests) {
158 if (base::Time::Now() - request->creation_time() >=
159 base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds)) {
160 expired_request_ids->push_back(request->request_id());
161 } else {
162 valid_requests->push_back(std::move(request));
163 }
164 }
165 }
166
167 // Filter out requests that don't meet the current conditions. For instance, if
168 // this is a predictive request, and we are not on WiFi, it should be ignored
169 // this round.
170 bool PickRequestTask::RequestConditionsSatisfied(
171 const SavePageRequest* request) {
172 // If the user did not request the page directly, make sure we are connected
173 // to power and have WiFi and sufficient battery remaining before we take this
174 // request.
175 if (!device_conditions_->IsPowerConnected() &&
176 policy_->PowerRequired(request->user_requested())) {
177 return false;
178 }
179
180 if (device_conditions_->GetNetConnectionType() !=
181 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI &&
182 policy_->UnmeteredNetworkRequired(request->user_requested())) {
183 return false;
184 }
185
186 if (device_conditions_->GetBatteryPercentage() <
187 policy_->BatteryPercentageRequired(request->user_requested())) {
188 return false;
189 }
190
191 // If we have already started this page the max number of times, it is not
192 // eligible to try again.
193 if (request->started_attempt_count() >= policy_->GetMaxStartedTries())
194 return false;
195
196 // If we have already completed trying this page the max number of times, it
197 // is not eligible to try again.
198 if (request->completed_attempt_count() >= policy_->GetMaxCompletedTries())
199 return false;
200
201 // If the request is paused, do not consider it.
202 if (request->request_state() == SavePageRequest::RequestState::PAUSED)
203 return false;
204
205 // If the request is expired, do not consider it.
206 base::TimeDelta requestAge = base::Time::Now() - request->creation_time();
207 if (requestAge > base::TimeDelta::FromSeconds(
208 policy_->GetRequestExpirationTimeInSeconds()))
209 return false;
210
211 // If this request is not active yet, return false.
212 // TODO(petewil): If the only reason we return nothing to do is that we have
213 // inactive requests, we still want to try again later after their activation
214 // time elapses, we shouldn't take ourselves completely off the scheduler.
215 if (request->activation_time() > base::Time::Now())
216 return false;
217
218 return true;
219 }
220
221 // Look at policies to decide which requests to prefer.
222 bool PickRequestTask::IsNewRequestBetter(const SavePageRequest* oldRequest,
223 const SavePageRequest* newRequest,
224 RequestCompareFunction comparator) {
225 // If there is no old request, the new one is better.
226 if (oldRequest == nullptr)
227 return true;
228
229 // User requested pages get priority.
230 if (newRequest->user_requested() && !oldRequest->user_requested())
231 return true;
232
233 // Otherwise, use the comparison function for the current policy, which
234 // returns true if the older request is better.
235 return !(CALL_MEMBER_FUNCTION(this, comparator)(oldRequest, newRequest));
236 }
237
238 // Compare the results, checking request count before recency. Returns true if
239 // left hand side is better, false otherwise.
240 bool PickRequestTask::RetryCountFirstCompareFunction(
241 const SavePageRequest* left,
242 const SavePageRequest* right) {
243 // Check the attempt count.
244 int result = CompareRetryCount(left, right);
245
246 if (result != 0)
247 return (result > 0);
248
249 // If we get here, the attempt counts were the same, so check recency.
250 result = CompareCreationTime(left, right);
251
252 return (result > 0);
253 }
254
255 // Compare the results, checking recency before request count. Returns true if
256 // left hand side is better, false otherwise.
257 bool PickRequestTask::RecencyFirstCompareFunction(
258 const SavePageRequest* left,
259 const SavePageRequest* right) {
260 // Check the recency.
261 int result = CompareCreationTime(left, right);
262
263 if (result != 0)
264 return (result > 0);
265
266 // If we get here, the recency was the same, so check the attempt count.
267 result = CompareRetryCount(left, right);
268
269 return (result > 0);
270 }
271
272 // Compare left and right side, returning 1 if the left side is better
273 // (preferred by policy), 0 if the same, and -1 if the right side is better.
274 int PickRequestTask::CompareRetryCount(const SavePageRequest* left,
275 const SavePageRequest* right) {
276 // Check the attempt count.
277 int result = signum(left->completed_attempt_count() -
278 right->completed_attempt_count());
279
280 // Flip the direction of comparison if policy prefers fewer retries.
281 if (policy_->ShouldPreferUntriedRequests())
282 result *= -1;
283
284 return result;
285 }
286
287 // Compare left and right side, returning 1 if the left side is better
288 // (preferred by policy), 0 if the same, and -1 if the right side is better.
289 int PickRequestTask::CompareCreationTime(const SavePageRequest* left,
290 const SavePageRequest* right) {
291 // Check the recency.
292 base::TimeDelta difference = left->creation_time() - right->creation_time();
293 int result = signum(difference.InMilliseconds());
294
295 // Flip the direction of comparison if policy prefers fewer retries.
296 if (policy_->ShouldPreferEarlierRequests())
297 result *= -1;
298
299 return result;
300 }
301
302 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698