| Index: components/offline_pages/background/pick_request_task.cc
|
| diff --git a/components/offline_pages/background/request_picker.cc b/components/offline_pages/background/pick_request_task.cc
|
| similarity index 57%
|
| rename from components/offline_pages/background/request_picker.cc
|
| rename to components/offline_pages/background/pick_request_task.cc
|
| index c1d27838165d837bb70bc28bf3768e63a597441d..3de14dd4d5cee57ed88d727ab8e41604cabc5829 100644
|
| --- a/components/offline_pages/background/request_picker.cc
|
| +++ b/components/offline_pages/background/pick_request_task.cc
|
| @@ -2,10 +2,16 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "components/offline_pages/background/request_picker.h"
|
| +#include "components/offline_pages/background/pick_request_task.h"
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "base/time/time.h"
|
| +#include "components/offline_pages/background/device_conditions.h"
|
| +#include "components/offline_pages/background/offliner_policy.h"
|
| +#include "components/offline_pages/background/request_coordinator_event_logger.h"
|
| +#include "components/offline_pages/background/request_notifier.h"
|
| +#include "components/offline_pages/background/request_queue_store.h"
|
| #include "components/offline_pages/background/save_page_request.h"
|
|
|
| namespace {
|
| @@ -19,62 +25,63 @@ int signum(T t) {
|
|
|
| namespace offline_pages {
|
|
|
| -RequestPicker::RequestPicker(RequestQueue* requestQueue,
|
| - OfflinerPolicy* policy,
|
| - RequestNotifier* notifier,
|
| - RequestCoordinatorEventLogger* event_logger)
|
| - : queue_(requestQueue),
|
| +PickRequestTask::PickRequestTask(RequestQueueStore* store,
|
| + OfflinerPolicy* policy,
|
| + RequestNotifier* notifier,
|
| + RequestCoordinatorEventLogger* event_logger,
|
| + RequestPickedCallback picked_callback,
|
| + RequestNotPickedCallback not_picked_callback,
|
| + DeviceConditions& device_conditions,
|
| + const std::set<int64_t>& disabled_requests)
|
| + : store_(store),
|
| policy_(policy),
|
| notifier_(notifier),
|
| event_logger_(event_logger),
|
| - fewer_retries_better_(false),
|
| - earlier_requests_better_(false),
|
| - weak_ptr_factory_(this) {}
|
| -
|
| -RequestPicker::~RequestPicker() {}
|
| -
|
| -// Entry point for the async operation to choose the next request.
|
| -void RequestPicker::ChooseNextRequest(
|
| - RequestCoordinator::RequestPickedCallback picked_callback,
|
| - RequestCoordinator::RequestNotPickedCallback not_picked_callback,
|
| - DeviceConditions* device_conditions,
|
| - const std::set<int64_t>& disabled_requests) {
|
| - picked_callback_ = picked_callback;
|
| - not_picked_callback_ = not_picked_callback;
|
| - fewer_retries_better_ = policy_->ShouldPreferUntriedRequests();
|
| - earlier_requests_better_ = policy_->ShouldPreferEarlierRequests();
|
| - current_conditions_.reset(new DeviceConditions(*device_conditions));
|
| - // Get all requests from queue (there is no filtering mechanism).
|
| - queue_->GetRequests(base::Bind(&RequestPicker::GetRequestResultCallback,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - disabled_requests));
|
| + picked_callback_(picked_callback),
|
| + not_picked_callback_(not_picked_callback),
|
| + disabled_requests_(disabled_requests),
|
| + weak_ptr_factory_(this) {
|
| + device_conditions_.reset(new DeviceConditions(device_conditions));
|
| }
|
|
|
| -// When we get contents from the queue, use them to pick the next
|
| -// request to operate on (if any).
|
| -void RequestPicker::GetRequestResultCallback(
|
| - const std::set<int64_t>& disabled_requests,
|
| - RequestQueue::GetRequestsResult,
|
| +PickRequestTask::~PickRequestTask() {}
|
| +
|
| +void PickRequestTask::Run() {
|
| + // Get all the requests from the queue, we will classify them in the callback.
|
| + store_->GetRequests(base::Bind(&PickRequestTask::ChooseAndPrune,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void PickRequestTask::ChooseAndPrune(
|
| + bool success,
|
| std::vector<std::unique_ptr<SavePageRequest>> requests) {
|
| // If there is nothing to do, return right away.
|
| if (requests.size() == 0) {
|
| not_picked_callback_.Run(false);
|
| + TaskComplete();
|
| return;
|
| }
|
|
|
| // Get the expired requests to be removed from the queue, and the valid ones
|
| // from which to pick the next request.
|
| std::vector<std::unique_ptr<SavePageRequest>> valid_requests;
|
| - std::vector<std::unique_ptr<SavePageRequest>> expired_requests;
|
| - SplitRequests(std::move(requests), &valid_requests, &expired_requests);
|
| std::vector<int64_t> expired_request_ids;
|
| - for (const auto& request : expired_requests)
|
| - expired_request_ids.push_back(request->request_id());
|
| + SplitRequests(std::move(requests), &valid_requests, &expired_request_ids);
|
|
|
| - queue_->RemoveRequests(expired_request_ids,
|
| - base::Bind(&RequestPicker::OnRequestExpired,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| + // Continue processing by choosing a request.
|
| + ChooseRequestAndCallback(std::move(valid_requests));
|
|
|
| + // Continue processing by handling expired requests, if any.
|
| + if (expired_request_ids.size() == 0) {
|
| + TaskComplete();
|
| + return;
|
| + }
|
| +
|
| + RemoveStaleRequests(std::move(expired_request_ids));
|
| +}
|
| +
|
| +void PickRequestTask::ChooseRequestAndCallback(
|
| + std::vector<std::unique_ptr<SavePageRequest>> valid_requests) {
|
| // Pick the most deserving request for our conditions.
|
| const SavePageRequest* picked_request = nullptr;
|
|
|
| @@ -82,18 +89,24 @@ void RequestPicker::GetRequestResultCallback(
|
|
|
| // Choose which comparison function to use based on policy.
|
| if (policy_->RetryCountIsMoreImportantThanRecency())
|
| - comparator = &RequestPicker::RetryCountFirstCompareFunction;
|
| + comparator = &PickRequestTask::RetryCountFirstCompareFunction;
|
| else
|
| - comparator = &RequestPicker::RecencyFirstCompareFunction;
|
| + comparator = &PickRequestTask::RecencyFirstCompareFunction;
|
|
|
| - // Iterate once through the requests, keeping track of best candidate.
|
| + // TODO(petewil): Consider replacing this bool with a better named enum.
|
| bool non_user_requested_tasks_remaining = false;
|
| +
|
| + // Iterate once through the requests, keeping track of best candidate.
|
| for (unsigned i = 0; i < valid_requests.size(); ++i) {
|
| // If the request is on the disabled list, skip it.
|
| - auto search = disabled_requests.find(valid_requests[i]->request_id());
|
| - if (search != disabled_requests.end()) {
|
| + auto search = disabled_requests_.find(valid_requests[i]->request_id());
|
| + if (search != disabled_requests_.end())
|
| continue;
|
| - }
|
| + // If there are non-user-requested tasks remaining, we need to make sure
|
| + // that they are scheduled after we run out of user requested tasks. Here we
|
| + // detect if any exist. If we don't find any user-requested tasks, we will
|
| + // inform the "not_picked_callback_" that it needs to schedule a task for
|
| + // non-user-requested items, which have different network and power needs.
|
| if (!valid_requests[i]->user_requested())
|
| non_user_requested_tasks_remaining = true;
|
| if (!RequestConditionsSatisfied(valid_requests[i].get()))
|
| @@ -104,33 +117,73 @@ void RequestPicker::GetRequestResultCallback(
|
|
|
| // If we have a best request to try next, get the request coodinator to
|
| // start it. Otherwise return that we have no candidates.
|
| - if (picked_request != nullptr) {
|
| + if (picked_request != nullptr)
|
| picked_callback_.Run(*picked_request);
|
| - } else {
|
| + else
|
| not_picked_callback_.Run(non_user_requested_tasks_remaining);
|
| +}
|
| +
|
| +// Continue the async part of the processing by deleting the expired requests.
|
| +// TODO(petewil): Does that really need to be done on the task queue? Hard to
|
| +// see how we need to wait for it before starting the next task. OTOH, we'd hate
|
| +// to do a second slow DB operation to get entries a second time, and waiting
|
| +// until this is done will make sure other gets don't see these old entries.
|
| +// Consider moving this to a fresh task type to clean the queue.
|
| +void PickRequestTask::RemoveStaleRequests(
|
| + std::vector<int64_t> stale_request_ids) {
|
| + store_->RemoveRequests(stale_request_ids,
|
| + base::Bind(&PickRequestTask::OnRequestsExpired,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void PickRequestTask::OnRequestsExpired(
|
| + std::unique_ptr<UpdateRequestsResult> result) {
|
| + RequestNotifier::BackgroundSavePageResult save_page_result(
|
| + RequestNotifier::BackgroundSavePageResult::EXPIRED);
|
| + for (const auto& request : result->updated_items) {
|
| + event_logger_->RecordDroppedSavePageRequest(
|
| + request.client_id().name_space, save_page_result, request.request_id());
|
| + notifier_->NotifyCompleted(request, save_page_result);
|
| + }
|
| +
|
| + // The task is now done, return control to the task queue.
|
| + TaskComplete();
|
| +}
|
| +
|
| +void PickRequestTask::SplitRequests(
|
| + std::vector<std::unique_ptr<SavePageRequest>> requests,
|
| + std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
|
| + std::vector<int64_t>* expired_request_ids) {
|
| + for (auto& request : requests) {
|
| + if (base::Time::Now() - request->creation_time() >=
|
| + base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds)) {
|
| + expired_request_ids->push_back(request->request_id());
|
| + } else {
|
| + valid_requests->push_back(std::move(request));
|
| + }
|
| }
|
| }
|
|
|
| // Filter out requests that don't meet the current conditions. For instance, if
|
| // this is a predictive request, and we are not on WiFi, it should be ignored
|
| // this round.
|
| -bool RequestPicker::RequestConditionsSatisfied(const SavePageRequest* request) {
|
| +bool PickRequestTask::RequestConditionsSatisfied(
|
| + const SavePageRequest* request) {
|
| // If the user did not request the page directly, make sure we are connected
|
| // to power and have WiFi and sufficient battery remaining before we take this
|
| // request.
|
| -
|
| - if (!current_conditions_->IsPowerConnected() &&
|
| + if (!device_conditions_->IsPowerConnected() &&
|
| policy_->PowerRequired(request->user_requested())) {
|
| return false;
|
| }
|
|
|
| - if (current_conditions_->GetNetConnectionType() !=
|
| + if (device_conditions_->GetNetConnectionType() !=
|
| net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI &&
|
| policy_->UnmeteredNetworkRequired(request->user_requested())) {
|
| return false;
|
| }
|
|
|
| - if (current_conditions_->GetBatteryPercentage() <
|
| + if (device_conditions_->GetBatteryPercentage() <
|
| policy_->BatteryPercentageRequired(request->user_requested())) {
|
| return false;
|
| }
|
| @@ -151,9 +204,8 @@ bool RequestPicker::RequestConditionsSatisfied(const SavePageRequest* request) {
|
|
|
| // If the request is expired, do not consider it.
|
| base::TimeDelta requestAge = base::Time::Now() - request->creation_time();
|
| - if (requestAge >
|
| - base::TimeDelta::FromSeconds(
|
| - policy_->GetRequestExpirationTimeInSeconds()))
|
| + if (requestAge > base::TimeDelta::FromSeconds(
|
| + policy_->GetRequestExpirationTimeInSeconds()))
|
| return false;
|
|
|
| // If this request is not active yet, return false.
|
| @@ -167,10 +219,9 @@ bool RequestPicker::RequestConditionsSatisfied(const SavePageRequest* request) {
|
| }
|
|
|
| // Look at policies to decide which requests to prefer.
|
| -bool RequestPicker::IsNewRequestBetter(const SavePageRequest* oldRequest,
|
| - const SavePageRequest* newRequest,
|
| - RequestCompareFunction comparator) {
|
| -
|
| +bool PickRequestTask::IsNewRequestBetter(const SavePageRequest* oldRequest,
|
| + const SavePageRequest* newRequest,
|
| + RequestCompareFunction comparator) {
|
| // If there is no old request, the new one is better.
|
| if (oldRequest == nullptr)
|
| return true;
|
| @@ -186,8 +237,9 @@ bool RequestPicker::IsNewRequestBetter(const SavePageRequest* oldRequest,
|
|
|
| // Compare the results, checking request count before recency. Returns true if
|
| // left hand side is better, false otherwise.
|
| -bool RequestPicker::RetryCountFirstCompareFunction(
|
| - const SavePageRequest* left, const SavePageRequest* right) {
|
| +bool PickRequestTask::RetryCountFirstCompareFunction(
|
| + const SavePageRequest* left,
|
| + const SavePageRequest* right) {
|
| // Check the attempt count.
|
| int result = CompareRetryCount(left, right);
|
|
|
| @@ -202,8 +254,9 @@ bool RequestPicker::RetryCountFirstCompareFunction(
|
|
|
| // Compare the results, checking recency before request count. Returns true if
|
| // left hand side is better, false otherwise.
|
| -bool RequestPicker::RecencyFirstCompareFunction(
|
| - const SavePageRequest* left, const SavePageRequest* right) {
|
| +bool PickRequestTask::RecencyFirstCompareFunction(
|
| + const SavePageRequest* left,
|
| + const SavePageRequest* right) {
|
| // Check the recency.
|
| int result = CompareCreationTime(left, right);
|
|
|
| @@ -218,14 +271,14 @@ bool RequestPicker::RecencyFirstCompareFunction(
|
|
|
| // Compare left and right side, returning 1 if the left side is better
|
| // (preferred by policy), 0 if the same, and -1 if the right side is better.
|
| -int RequestPicker::CompareRetryCount(
|
| - const SavePageRequest* left, const SavePageRequest* right) {
|
| +int PickRequestTask::CompareRetryCount(const SavePageRequest* left,
|
| + const SavePageRequest* right) {
|
| // Check the attempt count.
|
| int result = signum(left->completed_attempt_count() -
|
| right->completed_attempt_count());
|
|
|
| // Flip the direction of comparison if policy prefers fewer retries.
|
| - if (fewer_retries_better_)
|
| + if (policy_->ShouldPreferUntriedRequests())
|
| result *= -1;
|
|
|
| return result;
|
| @@ -233,44 +286,17 @@ int RequestPicker::CompareRetryCount(
|
|
|
| // Compare left and right side, returning 1 if the left side is better
|
| // (preferred by policy), 0 if the same, and -1 if the right side is better.
|
| -int RequestPicker::CompareCreationTime(
|
| - const SavePageRequest* left, const SavePageRequest* right) {
|
| +int PickRequestTask::CompareCreationTime(const SavePageRequest* left,
|
| + const SavePageRequest* right) {
|
| // Check the recency.
|
| base::TimeDelta difference = left->creation_time() - right->creation_time();
|
| int result = signum(difference.InMilliseconds());
|
|
|
| // Flip the direction of comparison if policy prefers fewer retries.
|
| - if (earlier_requests_better_)
|
| + if (policy_->ShouldPreferEarlierRequests())
|
| result *= -1;
|
|
|
| return result;
|
| }
|
|
|
| -void RequestPicker::SplitRequests(
|
| - std::vector<std::unique_ptr<SavePageRequest>> requests,
|
| - std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
|
| - std::vector<std::unique_ptr<SavePageRequest>>* expired_requests) {
|
| - for (auto& request : requests) {
|
| - if (base::Time::Now() - request->creation_time() >=
|
| - base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds)) {
|
| - expired_requests->push_back(std::move(request));
|
| - } else {
|
| - valid_requests->push_back(std::move(request));
|
| - }
|
| - }
|
| -}
|
| -
|
| -// Callback used after expired requests are deleted from the queue and notifies
|
| -// the coordinator.
|
| -void RequestPicker::OnRequestExpired(
|
| - std::unique_ptr<UpdateRequestsResult> result) {
|
| - const RequestCoordinator::BackgroundSavePageResult save_page_result(
|
| - RequestCoordinator::BackgroundSavePageResult::EXPIRED);
|
| - for (const auto& request : result->updated_items) {
|
| - event_logger_->RecordDroppedSavePageRequest(
|
| - request.client_id().name_space, save_page_result, request.request_id());
|
| - notifier_->NotifyCompleted(request, save_page_result);
|
| - }
|
| -}
|
| -
|
| } // namespace offline_pages
|
|
|