Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/request_coordinator.h" | 5 #include "components/offline_pages/background/request_coordinator.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
| 14 #include "components/offline_pages/background/offliner_factory.h" | 14 #include "components/offline_pages/background/offliner_factory.h" |
| 15 #include "components/offline_pages/background/offliner_policy.h" | 15 #include "components/offline_pages/background/offliner_policy.h" |
| 16 #include "components/offline_pages/background/request_picker.h" | 16 #include "components/offline_pages/background/request_picker.h" |
| 17 #include "components/offline_pages/background/save_page_request.h" | 17 #include "components/offline_pages/background/save_page_request.h" |
| 18 #include "components/offline_pages/offline_page_item.h" | 18 #include "components/offline_pages/offline_page_item.h" |
| 19 #include "components/offline_pages/offline_page_model.h" | |
| 19 | 20 |
| 20 namespace offline_pages { | 21 namespace offline_pages { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 // Records the final request status UMA for an offlining request. This should | 25 // Records the final request status UMA for an offlining request. This should |
| 25 // only be called once per Offliner::LoadAndSave request. | 26 // only be called once per Offliner::LoadAndSave request. |
| 26 void RecordOfflinerResultUMA(Offliner::RequestStatus request_status) { | 27 void RecordOfflinerResultUMA(Offliner::RequestStatus request_status) { |
| 27 UMA_HISTOGRAM_ENUMERATION("OfflinePages.Background.OfflinerRequestStatus", | 28 UMA_HISTOGRAM_ENUMERATION("OfflinePages.Background.OfflinerRequestStatus", |
| 28 request_status, | 29 request_status, |
| 29 Offliner::RequestStatus::STATUS_COUNT); | 30 Offliner::RequestStatus::STATUS_COUNT); |
| 30 } | 31 } |
| 31 | 32 |
| 32 } // namespace | 33 } // namespaceconst std::string& |
|
fgorski
2016/08/04 16:51:50
fix the accidental paste, please.
dougarnett
2016/08/04 16:57:20
ug, thanks!
| |
| 33 | 34 |
| 34 RequestCoordinator::RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy, | 35 RequestCoordinator::RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy, |
| 35 std::unique_ptr<OfflinerFactory> factory, | 36 std::unique_ptr<OfflinerFactory> factory, |
| 36 std::unique_ptr<RequestQueue> queue, | 37 std::unique_ptr<RequestQueue> queue, |
| 37 std::unique_ptr<Scheduler> scheduler) | 38 std::unique_ptr<Scheduler> scheduler) |
| 38 : is_busy_(false), | 39 : is_busy_(false), |
| 39 is_canceled_(false), | 40 is_canceled_(false), |
| 40 offliner_(nullptr), | 41 offliner_(nullptr), |
| 41 policy_(std::move(policy)), | 42 policy_(std::move(policy)), |
| 42 factory_(std::move(factory)), | 43 factory_(std::move(factory)), |
| 43 queue_(std::move(queue)), | 44 queue_(std::move(queue)), |
| 44 scheduler_(std::move(scheduler)), | 45 scheduler_(std::move(scheduler)), |
| 45 last_offlining_status_(Offliner::RequestStatus::UNKNOWN), | 46 last_offlining_status_(Offliner::RequestStatus::UNKNOWN), |
| 46 offliner_timeout_(base::TimeDelta::FromSeconds( | 47 offliner_timeout_(base::TimeDelta::FromSeconds( |
| 47 policy_->GetSinglePageTimeLimitInSeconds())), | 48 policy_->GetSinglePageTimeLimitInSeconds())), |
| 48 weak_ptr_factory_(this) { | 49 weak_ptr_factory_(this) { |
| 49 DCHECK(policy_ != nullptr); | 50 DCHECK(policy_ != nullptr); |
| 50 picker_.reset(new RequestPicker(queue_.get(), policy_.get())); | 51 picker_.reset(new RequestPicker(queue_.get(), policy_.get())); |
| 51 } | 52 } |
| 52 | 53 |
| 53 RequestCoordinator::~RequestCoordinator() {} | 54 RequestCoordinator::~RequestCoordinator() {} |
| 54 | 55 |
| 55 bool RequestCoordinator::SavePageLater( | 56 bool RequestCoordinator::SavePageLater( |
| 56 const GURL& url, const ClientId& client_id, bool was_user_requested) { | 57 const GURL& url, const ClientId& client_id, bool was_user_requested) { |
| 57 DVLOG(2) << "URL is " << url << " " << __func__; | 58 DVLOG(2) << "URL is " << url << " " << __func__; |
| 58 | 59 |
| 60 if (!OfflinePageModel::CanSaveURL(url)) { | |
| 61 DVLOG(1) << "Not able to save page for requested url: " << url; | |
| 62 return false; | |
| 63 } | |
| 64 | |
| 59 // TODO(petewil): We need a robust scheme for allocating new IDs. | 65 // TODO(petewil): We need a robust scheme for allocating new IDs. |
| 60 static int64_t id = 0; | 66 static int64_t id = 0; |
| 61 | 67 |
| 62 // Build a SavePageRequest. | 68 // Build a SavePageRequest. |
| 63 offline_pages::SavePageRequest request( | 69 offline_pages::SavePageRequest request( |
| 64 id++, url, client_id, base::Time::Now(), was_user_requested); | 70 id++, url, client_id, base::Time::Now(), was_user_requested); |
| 65 | 71 |
| 66 // Put the request on the request queue. | 72 // Put the request on the request queue. |
| 67 queue_->AddRequest(request, | 73 queue_->AddRequest(request, |
| 68 base::Bind(&RequestCoordinator::AddRequestResultCallback, | 74 base::Bind(&RequestCoordinator::AddRequestResultCallback, |
| 69 weak_ptr_factory_.GetWeakPtr())); | 75 weak_ptr_factory_.GetWeakPtr())); |
| 70 return true; | 76 return true; |
| 71 } | 77 } |
| 72 | 78 |
| 73 void RequestCoordinator::RemoveRequests( | 79 void RequestCoordinator::RemoveRequests( |
| 74 const std::vector<ClientId>& client_ids) { | 80 const std::vector<ClientId>& client_ids) { |
| 75 queue_->RemoveRequestsByClientId( | 81 queue_->RemoveRequestsByClientId( |
| 76 client_ids, base::Bind(&RequestCoordinator::UpdateRequestCallback, | 82 client_ids, base::Bind(&RequestCoordinator::UpdateMultipleRequestCallback, |
| 77 weak_ptr_factory_.GetWeakPtr())); | 83 weak_ptr_factory_.GetWeakPtr())); |
| 78 } | 84 } |
| 79 | 85 |
| 80 void RequestCoordinator::AddRequestResultCallback( | 86 void RequestCoordinator::AddRequestResultCallback( |
| 81 RequestQueue::AddRequestResult result, | 87 RequestQueue::AddRequestResult result, |
| 82 const SavePageRequest& request) { | 88 const SavePageRequest& request) { |
| 83 | 89 |
| 84 // Inform the scheduler that we have an outstanding task.. | 90 // Inform the scheduler that we have an outstanding task.. |
| 85 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); | 91 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); |
| 86 } | 92 } |
| 87 | 93 |
| 88 // Called in response to updating a request in the request queue. | 94 // Called in response to updating a request in the request queue. |
| 89 void RequestCoordinator::UpdateRequestCallback( | 95 void RequestCoordinator::UpdateRequestCallback( |
| 96 const ClientId& client_id, | |
| 90 RequestQueue::UpdateRequestResult result) { | 97 RequestQueue::UpdateRequestResult result) { |
| 91 // If the request succeeded, nothing to do. If it failed, we can't really do | 98 // If the request succeeded, nothing to do. If it failed, we can't really do |
| 92 // much, so just log it. | 99 // much, so just log it. |
| 93 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | 100 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { |
| 94 // TODO(petewil): Consider adding UMA or showing on offline-internals page. | 101 DVLOG(1) << "Failed to update request attempt details. " |
| 95 DLOG(WARNING) << "Failed to update a request retry count. " | 102 << static_cast<int>(result); |
| 96 << static_cast<int>(result); | 103 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result); |
| 104 } | |
| 105 } | |
| 106 | |
| 107 // Called in response to updating multiple requests in the request queue. | |
| 108 void RequestCoordinator::UpdateMultipleRequestCallback( | |
| 109 RequestQueue::UpdateRequestResult result) { | |
| 110 // If the request succeeded, nothing to do. If it failed, we can't really do | |
| 111 // much, so just log it. | |
| 112 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | |
| 113 DVLOG(1) << "Failed to update request attempt details. " | |
| 114 << static_cast<int>(result); | |
| 97 } | 115 } |
| 98 } | 116 } |
| 99 | 117 |
| 100 void RequestCoordinator::StopProcessing() { | 118 void RequestCoordinator::StopProcessing() { |
| 101 is_canceled_ = true; | 119 is_canceled_ = true; |
| 102 if (offliner_ && is_busy_) | 120 if (offliner_ && is_busy_) { |
| 121 // TODO(dougarnett): Find current request and mark attempt aborted. | |
| 103 offliner_->Cancel(); | 122 offliner_->Cancel(); |
| 123 } | |
| 104 | 124 |
| 105 // Stopping offliner means it will not call callback. | 125 // Stopping offliner means it will not call callback. |
| 106 last_offlining_status_ = | 126 last_offlining_status_ = |
| 107 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; | 127 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; |
| 108 RecordOfflinerResultUMA(last_offlining_status_); | 128 RecordOfflinerResultUMA(last_offlining_status_); |
| 109 | 129 |
| 110 // Let the scheduler know we are done processing. | 130 // Let the scheduler know we are done processing. |
| 111 scheduler_callback_.Run(true); | 131 scheduler_callback_.Run(true); |
| 112 } | 132 } |
| 113 | 133 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 GetOffliner(); | 197 GetOffliner(); |
| 178 if (!offliner_) { | 198 if (!offliner_) { |
| 179 DVLOG(0) << "Unable to create Offliner. " | 199 DVLOG(0) << "Unable to create Offliner. " |
| 180 << "Cannot background offline page."; | 200 << "Cannot background offline page."; |
| 181 return; | 201 return; |
| 182 } | 202 } |
| 183 | 203 |
| 184 DCHECK(!is_busy_); | 204 DCHECK(!is_busy_); |
| 185 is_busy_ = true; | 205 is_busy_ = true; |
| 186 | 206 |
| 207 // Prepare an updated request to attempt. | |
| 208 SavePageRequest updated_request(request); | |
| 209 updated_request.MarkAttemptStarted(base::Time::Now()); | |
| 210 | |
| 187 // Start the load and save process in the offliner (Async). | 211 // Start the load and save process in the offliner (Async). |
| 188 offliner_->LoadAndSave(request, | 212 if (offliner_->LoadAndSave( |
| 189 base::Bind(&RequestCoordinator::OfflinerDoneCallback, | 213 updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback, |
| 190 weak_ptr_factory_.GetWeakPtr())); | 214 weak_ptr_factory_.GetWeakPtr()))) { |
| 215 // Offliner accepted request so update it in the queue. | |
| 216 queue_->UpdateRequest(updated_request, | |
| 217 base::Bind(&RequestCoordinator::UpdateRequestCallback, | |
| 218 weak_ptr_factory_.GetWeakPtr(), | |
| 219 updated_request.client_id())); | |
| 191 | 220 |
| 192 // Start a watchdog timer to catch pre-renders running too long | 221 // Start a watchdog timer to catch pre-renders running too long |
| 193 watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this, | 222 watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this, |
| 194 &RequestCoordinator::StopProcessing); | 223 &RequestCoordinator::StopProcessing); |
| 224 } else { | |
| 225 is_busy_ = false; | |
| 226 DVLOG(0) << "Unable to start LoadAndSave"; | |
| 227 StopProcessing(); | |
| 228 } | |
| 195 } | 229 } |
| 196 | 230 |
| 197 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request, | 231 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request, |
| 198 Offliner::RequestStatus status) { | 232 Offliner::RequestStatus status) { |
| 199 DVLOG(2) << "offliner finished, saved: " | 233 DVLOG(2) << "offliner finished, saved: " |
| 200 << (status == Offliner::RequestStatus::SAVED) | 234 << (status == Offliner::RequestStatus::SAVED) |
| 201 << ", status: " << static_cast<int>(status) << ", " << __func__; | 235 << ", status: " << static_cast<int>(status) << ", " << __func__; |
| 202 DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN); | 236 DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN); |
| 203 DCHECK_NE(status, Offliner::RequestStatus::LOADED); | 237 DCHECK_NE(status, Offliner::RequestStatus::LOADED); |
| 204 event_logger_.RecordSavePageRequestUpdated( | 238 event_logger_.RecordSavePageRequestUpdated(request.client_id().name_space, |
| 205 request.client_id().name_space, | 239 status, request.request_id()); |
| 206 "Saved", | |
| 207 request.request_id()); | |
| 208 last_offlining_status_ = status; | 240 last_offlining_status_ = status; |
| 209 RecordOfflinerResultUMA(last_offlining_status_); | 241 RecordOfflinerResultUMA(last_offlining_status_); |
| 210 watchdog_timer_.Stop(); | 242 watchdog_timer_.Stop(); |
| 211 | 243 |
| 212 is_busy_ = false; | 244 is_busy_ = false; |
| 213 | 245 |
| 214 int64_t new_attempt_count = request.attempt_count() + 1; | 246 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) { |
| 247 // Update the request for the canceled attempt. | |
| 248 // TODO(dougarnett): See if we can conclusively identify other attempt | |
| 249 // aborted cases to treat this way (eg, for Render Process Killed). | |
| 250 SavePageRequest updated_request(request); | |
| 251 updated_request.MarkAttemptAborted(); | |
| 252 queue_->UpdateRequest(updated_request, | |
| 253 base::Bind(&RequestCoordinator::UpdateRequestCallback, | |
| 254 weak_ptr_factory_.GetWeakPtr(), | |
| 255 updated_request.client_id())); | |
| 215 | 256 |
| 216 // Remove the request from the queue if it either succeeded or exceeded the | 257 } else if (status == Offliner::RequestStatus::SAVED || |
| 217 // max number of retries. | 258 request.attempt_count() >= policy_->GetMaxTries()) { |
| 218 if (status == Offliner::RequestStatus::SAVED | 259 // Remove the request from the queue if it either succeeded or exceeded the |
| 219 || new_attempt_count > policy_->GetMaxTries()) { | 260 // max number of retries. |
| 220 queue_->RemoveRequest(request.request_id(), | 261 queue_->RemoveRequest( |
| 221 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 262 request.request_id(), |
| 222 weak_ptr_factory_.GetWeakPtr())); | 263 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 264 weak_ptr_factory_.GetWeakPtr(), request.client_id())); | |
| 223 } else { | 265 } else { |
| 224 // If we failed, but are not over the limit, update the request in the | 266 // If we failed, but are not over the limit, update the request in the |
| 225 // queue. | 267 // queue. |
| 226 SavePageRequest updated_request(request); | 268 SavePageRequest updated_request(request); |
| 227 updated_request.set_attempt_count(new_attempt_count); | 269 updated_request.MarkAttemptCompleted(); |
| 228 updated_request.set_last_attempt_time(base::Time::Now()); | 270 queue_->UpdateRequest(updated_request, |
| 229 RequestQueue::UpdateRequestCallback update_callback = | 271 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 230 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 272 weak_ptr_factory_.GetWeakPtr(), |
| 231 weak_ptr_factory_.GetWeakPtr()); | 273 updated_request.client_id())); |
| 232 queue_->UpdateRequest( | |
| 233 updated_request, | |
| 234 base::Bind(&RequestCoordinator::UpdateRequestCallback, | |
| 235 weak_ptr_factory_.GetWeakPtr())); | |
| 236 } | 274 } |
| 237 | 275 |
| 238 // Determine whether we might try another request in this | 276 // Determine whether we might try another request in this |
| 239 // processing window based on how the previous request completed. | 277 // processing window based on how the previous request completed. |
| 240 // | 278 // |
| 241 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate | 279 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate |
| 242 // codes as to whether we should try another request or not. | 280 // codes as to whether we should try another request or not. |
| 243 switch (status) { | 281 switch (status) { |
| 244 case Offliner::RequestStatus::SAVED: | 282 case Offliner::RequestStatus::SAVED: |
| 245 case Offliner::RequestStatus::SAVE_FAILED: | 283 case Offliner::RequestStatus::SAVE_FAILED: |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 268 return trigger_conditions; | 306 return trigger_conditions; |
| 269 } | 307 } |
| 270 | 308 |
| 271 void RequestCoordinator::GetOffliner() { | 309 void RequestCoordinator::GetOffliner() { |
| 272 if (!offliner_) { | 310 if (!offliner_) { |
| 273 offliner_ = factory_->GetOffliner(policy_.get()); | 311 offliner_ = factory_->GetOffliner(policy_.get()); |
| 274 } | 312 } |
| 275 } | 313 } |
| 276 | 314 |
| 277 } // namespace offline_pages | 315 } // namespace offline_pages |
| OLD | NEW |