| 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, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 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, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 92 if (client_namespace == request.client_id().name_space) | 98 if (client_namespace == request.client_id().name_space) |
| 93 client_ids.push_back(request.client_id()); | 99 client_ids.push_back(request.client_id()); |
| 94 } | 100 } |
| 95 | 101 |
| 96 callback.Run(client_ids); | 102 callback.Run(client_ids); |
| 97 } | 103 } |
| 98 | 104 |
| 99 void RequestCoordinator::RemoveRequests( | 105 void RequestCoordinator::RemoveRequests( |
| 100 const std::vector<ClientId>& client_ids) { | 106 const std::vector<ClientId>& client_ids) { |
| 101 queue_->RemoveRequestsByClientId( | 107 queue_->RemoveRequestsByClientId( |
| 102 client_ids, base::Bind(&RequestCoordinator::UpdateRequestCallback, | 108 client_ids, base::Bind(&RequestCoordinator::UpdateMultipleRequestCallback, |
| 103 weak_ptr_factory_.GetWeakPtr())); | 109 weak_ptr_factory_.GetWeakPtr())); |
| 104 } | 110 } |
| 105 | 111 |
| 106 void RequestCoordinator::AddRequestResultCallback( | 112 void RequestCoordinator::AddRequestResultCallback( |
| 107 RequestQueue::AddRequestResult result, | 113 RequestQueue::AddRequestResult result, |
| 108 const SavePageRequest& request) { | 114 const SavePageRequest& request) { |
| 109 | 115 |
| 110 // Inform the scheduler that we have an outstanding task.. | 116 // Inform the scheduler that we have an outstanding task.. |
| 111 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); | 117 scheduler_->Schedule(GetTriggerConditionsForUserRequest()); |
| 112 } | 118 } |
| 113 | 119 |
| 114 // Called in response to updating a request in the request queue. | 120 // Called in response to updating a request in the request queue. |
| 115 void RequestCoordinator::UpdateRequestCallback( | 121 void RequestCoordinator::UpdateRequestCallback( |
| 122 const ClientId& client_id, |
| 116 RequestQueue::UpdateRequestResult result) { | 123 RequestQueue::UpdateRequestResult result) { |
| 117 // If the request succeeded, nothing to do. If it failed, we can't really do | 124 // If the request succeeded, nothing to do. If it failed, we can't really do |
| 118 // much, so just log it. | 125 // much, so just log it. |
| 119 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { | 126 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { |
| 120 // TODO(petewil): Consider adding UMA or showing on offline-internals page. | 127 DVLOG(1) << "Failed to update request attempt details. " |
| 121 DLOG(WARNING) << "Failed to update a request retry count. " | 128 << static_cast<int>(result); |
| 122 << static_cast<int>(result); | 129 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result); |
| 130 } |
| 131 } |
| 132 |
| 133 // Called in response to updating multiple requests in the request queue. |
| 134 void RequestCoordinator::UpdateMultipleRequestCallback( |
| 135 RequestQueue::UpdateRequestResult result) { |
| 136 // If the request succeeded, nothing to do. If it failed, we can't really do |
| 137 // much, so just log it. |
| 138 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { |
| 139 DVLOG(1) << "Failed to update request attempt details. " |
| 140 << static_cast<int>(result); |
| 123 } | 141 } |
| 124 } | 142 } |
| 125 | 143 |
| 126 void RequestCoordinator::StopProcessing() { | 144 void RequestCoordinator::StopProcessing() { |
| 127 is_canceled_ = true; | 145 is_canceled_ = true; |
| 128 if (offliner_ && is_busy_) | 146 if (offliner_ && is_busy_) { |
| 147 // TODO(dougarnett): Find current request and mark attempt aborted. |
| 129 offliner_->Cancel(); | 148 offliner_->Cancel(); |
| 149 } |
| 130 | 150 |
| 131 // Stopping offliner means it will not call callback. | 151 // Stopping offliner means it will not call callback. |
| 132 last_offlining_status_ = | 152 last_offlining_status_ = |
| 133 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; | 153 Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED; |
| 134 RecordOfflinerResultUMA(last_offlining_status_); | 154 RecordOfflinerResultUMA(last_offlining_status_); |
| 135 | 155 |
| 136 // Let the scheduler know we are done processing. | 156 // Let the scheduler know we are done processing. |
| 137 scheduler_callback_.Run(true); | 157 scheduler_callback_.Run(true); |
| 138 } | 158 } |
| 139 | 159 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 GetOffliner(); | 223 GetOffliner(); |
| 204 if (!offliner_) { | 224 if (!offliner_) { |
| 205 DVLOG(0) << "Unable to create Offliner. " | 225 DVLOG(0) << "Unable to create Offliner. " |
| 206 << "Cannot background offline page."; | 226 << "Cannot background offline page."; |
| 207 return; | 227 return; |
| 208 } | 228 } |
| 209 | 229 |
| 210 DCHECK(!is_busy_); | 230 DCHECK(!is_busy_); |
| 211 is_busy_ = true; | 231 is_busy_ = true; |
| 212 | 232 |
| 233 // Prepare an updated request to attempt. |
| 234 SavePageRequest updated_request(request); |
| 235 updated_request.MarkAttemptStarted(base::Time::Now()); |
| 236 |
| 213 // Start the load and save process in the offliner (Async). | 237 // Start the load and save process in the offliner (Async). |
| 214 offliner_->LoadAndSave(request, | 238 if (offliner_->LoadAndSave( |
| 215 base::Bind(&RequestCoordinator::OfflinerDoneCallback, | 239 updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback, |
| 216 weak_ptr_factory_.GetWeakPtr())); | 240 weak_ptr_factory_.GetWeakPtr()))) { |
| 241 // Offliner accepted request so update it in the queue. |
| 242 queue_->UpdateRequest(updated_request, |
| 243 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 244 weak_ptr_factory_.GetWeakPtr(), |
| 245 updated_request.client_id())); |
| 217 | 246 |
| 218 // Start a watchdog timer to catch pre-renders running too long | 247 // Start a watchdog timer to catch pre-renders running too long |
| 219 watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this, | 248 watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this, |
| 220 &RequestCoordinator::StopProcessing); | 249 &RequestCoordinator::StopProcessing); |
| 250 } else { |
| 251 is_busy_ = false; |
| 252 DVLOG(0) << "Unable to start LoadAndSave"; |
| 253 StopProcessing(); |
| 254 } |
| 221 } | 255 } |
| 222 | 256 |
| 223 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request, | 257 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request, |
| 224 Offliner::RequestStatus status) { | 258 Offliner::RequestStatus status) { |
| 225 DVLOG(2) << "offliner finished, saved: " | 259 DVLOG(2) << "offliner finished, saved: " |
| 226 << (status == Offliner::RequestStatus::SAVED) | 260 << (status == Offliner::RequestStatus::SAVED) |
| 227 << ", status: " << static_cast<int>(status) << ", " << __func__; | 261 << ", status: " << static_cast<int>(status) << ", " << __func__; |
| 228 DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN); | 262 DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN); |
| 229 DCHECK_NE(status, Offliner::RequestStatus::LOADED); | 263 DCHECK_NE(status, Offliner::RequestStatus::LOADED); |
| 230 event_logger_.RecordSavePageRequestUpdated( | 264 event_logger_.RecordSavePageRequestUpdated(request.client_id().name_space, |
| 231 request.client_id().name_space, | 265 status, request.request_id()); |
| 232 "Saved", | |
| 233 request.request_id()); | |
| 234 last_offlining_status_ = status; | 266 last_offlining_status_ = status; |
| 235 RecordOfflinerResultUMA(last_offlining_status_); | 267 RecordOfflinerResultUMA(last_offlining_status_); |
| 236 watchdog_timer_.Stop(); | 268 watchdog_timer_.Stop(); |
| 237 | 269 |
| 238 is_busy_ = false; | 270 is_busy_ = false; |
| 239 | 271 |
| 240 int64_t new_attempt_count = request.attempt_count() + 1; | 272 if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) { |
| 273 // Update the request for the canceled attempt. |
| 274 // TODO(dougarnett): See if we can conclusively identify other attempt |
| 275 // aborted cases to treat this way (eg, for Render Process Killed). |
| 276 SavePageRequest updated_request(request); |
| 277 updated_request.MarkAttemptAborted(); |
| 278 queue_->UpdateRequest(updated_request, |
| 279 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 280 weak_ptr_factory_.GetWeakPtr(), |
| 281 updated_request.client_id())); |
| 241 | 282 |
| 242 // Remove the request from the queue if it either succeeded or exceeded the | 283 } else if (status == Offliner::RequestStatus::SAVED || |
| 243 // max number of retries. | 284 request.attempt_count() >= policy_->GetMaxTries()) { |
| 244 if (status == Offliner::RequestStatus::SAVED | 285 // Remove the request from the queue if it either succeeded or exceeded the |
| 245 || new_attempt_count > policy_->GetMaxTries()) { | 286 // max number of retries. |
| 246 queue_->RemoveRequest(request.request_id(), | 287 queue_->RemoveRequest( |
| 247 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 288 request.request_id(), |
| 248 weak_ptr_factory_.GetWeakPtr())); | 289 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 290 weak_ptr_factory_.GetWeakPtr(), request.client_id())); |
| 249 } else { | 291 } else { |
| 250 // If we failed, but are not over the limit, update the request in the | 292 // If we failed, but are not over the limit, update the request in the |
| 251 // queue. | 293 // queue. |
| 252 SavePageRequest updated_request(request); | 294 SavePageRequest updated_request(request); |
| 253 updated_request.set_attempt_count(new_attempt_count); | 295 updated_request.MarkAttemptCompleted(); |
| 254 updated_request.set_last_attempt_time(base::Time::Now()); | 296 queue_->UpdateRequest(updated_request, |
| 255 RequestQueue::UpdateRequestCallback update_callback = | 297 base::Bind(&RequestCoordinator::UpdateRequestCallback, |
| 256 base::Bind(&RequestCoordinator::UpdateRequestCallback, | 298 weak_ptr_factory_.GetWeakPtr(), |
| 257 weak_ptr_factory_.GetWeakPtr()); | 299 updated_request.client_id())); |
| 258 queue_->UpdateRequest( | |
| 259 updated_request, | |
| 260 base::Bind(&RequestCoordinator::UpdateRequestCallback, | |
| 261 weak_ptr_factory_.GetWeakPtr())); | |
| 262 } | 300 } |
| 263 | 301 |
| 264 // Determine whether we might try another request in this | 302 // Determine whether we might try another request in this |
| 265 // processing window based on how the previous request completed. | 303 // processing window based on how the previous request completed. |
| 266 // | 304 // |
| 267 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate | 305 // TODO(dougarnett): Need to split PRERENDERING_FAILED into separate |
| 268 // codes as to whether we should try another request or not. | 306 // codes as to whether we should try another request or not. |
| 269 switch (status) { | 307 switch (status) { |
| 270 case Offliner::RequestStatus::SAVED: | 308 case Offliner::RequestStatus::SAVED: |
| 271 case Offliner::RequestStatus::SAVE_FAILED: | 309 case Offliner::RequestStatus::SAVE_FAILED: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 294 return trigger_conditions; | 332 return trigger_conditions; |
| 295 } | 333 } |
| 296 | 334 |
| 297 void RequestCoordinator::GetOffliner() { | 335 void RequestCoordinator::GetOffliner() { |
| 298 if (!offliner_) { | 336 if (!offliner_) { |
| 299 offliner_ = factory_->GetOffliner(policy_.get()); | 337 offliner_ = factory_->GetOffliner(policy_.get()); |
| 300 } | 338 } |
| 301 } | 339 } |
| 302 | 340 |
| 303 } // namespace offline_pages | 341 } // namespace offline_pages |
| OLD | NEW |