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

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

Issue 2420503002: [Offline Pages] Define separate watchdog timeout for concurrent bg loads (Closed)
Patch Set: Merge Created 4 years, 2 months 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/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"
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 114
115 RequestCoordinator::RequestCoordinator( 115 RequestCoordinator::RequestCoordinator(
116 std::unique_ptr<OfflinerPolicy> policy, 116 std::unique_ptr<OfflinerPolicy> policy,
117 std::unique_ptr<OfflinerFactory> factory, 117 std::unique_ptr<OfflinerFactory> factory,
118 std::unique_ptr<RequestQueue> queue, 118 std::unique_ptr<RequestQueue> queue,
119 std::unique_ptr<Scheduler> scheduler, 119 std::unique_ptr<Scheduler> scheduler,
120 net::NetworkQualityEstimator::NetworkQualityProvider* 120 net::NetworkQualityEstimator::NetworkQualityProvider*
121 network_quality_estimator) 121 network_quality_estimator)
122 : is_busy_(false), 122 : is_busy_(false),
123 is_starting_(false), 123 is_starting_(false),
124 is_stopped_(false), 124 processing_state_(ProcessingWindowState::STOPPED),
125 use_test_connection_type_(false), 125 use_test_connection_type_(false),
126 test_connection_type_(), 126 test_connection_type_(),
127 offliner_(nullptr), 127 offliner_(nullptr),
128 policy_(std::move(policy)), 128 policy_(std::move(policy)),
129 factory_(std::move(factory)), 129 factory_(std::move(factory)),
130 queue_(std::move(queue)), 130 queue_(std::move(queue)),
131 scheduler_(std::move(scheduler)), 131 scheduler_(std::move(scheduler)),
132 policy_controller_(new ClientPolicyController()), 132 policy_controller_(new ClientPolicyController()),
133 network_quality_estimator_(network_quality_estimator), 133 network_quality_estimator_(network_quality_estimator),
134 active_request_(nullptr), 134 active_request_(nullptr),
135 last_offlining_status_(Offliner::RequestStatus::UNKNOWN), 135 last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
136 offliner_timeout_(base::TimeDelta::FromSeconds(
137 policy_->GetSinglePageTimeLimitInSeconds())),
138 weak_ptr_factory_(this) { 136 weak_ptr_factory_(this) {
139 DCHECK(policy_ != nullptr); 137 DCHECK(policy_ != nullptr);
140 picker_.reset( 138 picker_.reset(
141 new RequestPicker(queue_.get(), policy_.get(), this, &event_logger_)); 139 new RequestPicker(queue_.get(), policy_.get(), this, &event_logger_));
142 } 140 }
143 141
144 RequestCoordinator::~RequestCoordinator() {} 142 RequestCoordinator::~RequestCoordinator() {}
145 143
146 int64_t RequestCoordinator::SavePageLater(const GURL& url, 144 int64_t RequestCoordinator::SavePageLater(const GURL& url,
147 const ClientId& client_id, 145 const ClientId& client_id,
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 } 315 }
318 316
319 void RequestCoordinator::AddRequestResultCallback( 317 void RequestCoordinator::AddRequestResultCallback(
320 RequestQueue::AddRequestResult result, 318 RequestQueue::AddRequestResult result,
321 const SavePageRequest& request) { 319 const SavePageRequest& request) {
322 NotifyAdded(request); 320 NotifyAdded(request);
323 // Inform the scheduler that we have an outstanding task. 321 // Inform the scheduler that we have an outstanding task.
324 scheduler_->Schedule(GetTriggerConditions(kUserRequest)); 322 scheduler_->Schedule(GetTriggerConditions(kUserRequest));
325 323
326 if (request.user_requested()) 324 if (request.user_requested())
327 StartProcessingIfConnected(); 325 StartImmediatelyIfConnected();
328 } 326 }
329 327
330 // Called in response to updating a request in the request queue. 328 // Called in response to updating a request in the request queue.
331 void RequestCoordinator::UpdateRequestCallback( 329 void RequestCoordinator::UpdateRequestCallback(
332 const ClientId& client_id, 330 const ClientId& client_id,
333 RequestQueue::UpdateRequestResult result) { 331 RequestQueue::UpdateRequestResult result) {
334 // If the request succeeded, nothing to do. If it failed, we can't really do 332 // If the request succeeded, nothing to do. If it failed, we can't really do
335 // much, so just log it. 333 // much, so just log it.
336 if (result != RequestQueue::UpdateRequestResult::SUCCESS) { 334 if (result != RequestQueue::UpdateRequestResult::SUCCESS) {
337 DVLOG(1) << "Failed to update request attempt details. " 335 DVLOG(1) << "Failed to update request attempt details. "
338 << static_cast<int>(result); 336 << static_cast<int>(result);
339 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result); 337 event_logger_.RecordUpdateRequestFailed(client_id.name_space, result);
340 } 338 }
341 } 339 }
342 340
343 void RequestCoordinator::UpdateMultipleRequestsCallback( 341 void RequestCoordinator::UpdateMultipleRequestsCallback(
344 std::unique_ptr<UpdateRequestsResult> result) { 342 std::unique_ptr<UpdateRequestsResult> result) {
345 for (const auto& request : result->updated_items) 343 for (const auto& request : result->updated_items)
346 NotifyChanged(request); 344 NotifyChanged(request);
347 345
348 bool available_user_request = false; 346 bool available_user_request = false;
349 for (const auto& request : result->updated_items) { 347 for (const auto& request : result->updated_items) {
350 if (!available_user_request && request.user_requested() && 348 if (!available_user_request && request.user_requested() &&
351 request.request_state() == SavePageRequest::RequestState::AVAILABLE) { 349 request.request_state() == SavePageRequest::RequestState::AVAILABLE) {
352 available_user_request = true; 350 available_user_request = true;
353 } 351 }
354 } 352 }
355 353
356 if (available_user_request) 354 if (available_user_request)
357 StartProcessingIfConnected(); 355 StartImmediatelyIfConnected();
358 } 356 }
359 357
360 // When we successfully remove a request that completed successfully, move on to 358 // When we successfully remove a request that completed successfully, move on to
361 // the next request. 359 // the next request.
362 void RequestCoordinator::CompletedRequestCallback( 360 void RequestCoordinator::CompletedRequestCallback(
363 const MultipleItemStatuses& status) { 361 const MultipleItemStatuses& status) {
364 TryNextRequest(); 362 TryNextRequest();
365 } 363 }
366 364
367 void RequestCoordinator::HandleRemovedRequestsAndCallback( 365 void RequestCoordinator::HandleRemovedRequestsAndCallback(
(...skipping 17 matching lines...) Expand all
385 383
386 void RequestCoordinator::ScheduleAsNeeded() { 384 void RequestCoordinator::ScheduleAsNeeded() {
387 // Get all requests from queue (there is no filtering mechanism). 385 // Get all requests from queue (there is no filtering mechanism).
388 queue_->GetRequests( 386 queue_->GetRequests(
389 base::Bind(&RequestCoordinator::GetRequestsForSchedulingCallback, 387 base::Bind(&RequestCoordinator::GetRequestsForSchedulingCallback,
390 weak_ptr_factory_.GetWeakPtr())); 388 weak_ptr_factory_.GetWeakPtr()));
391 } 389 }
392 390
393 void RequestCoordinator::StopProcessing( 391 void RequestCoordinator::StopProcessing(
394 Offliner::RequestStatus stop_status) { 392 Offliner::RequestStatus stop_status) {
395 is_stopped_ = true; 393 processing_state_ = ProcessingWindowState::STOPPED;
396 StopPrerendering(stop_status); 394 StopPrerendering(stop_status);
397 395
398 // Let the scheduler know we are done processing. 396 // Let the scheduler know we are done processing.
399 scheduler_callback_.Run(true); 397 scheduler_callback_.Run(true);
400 } 398 }
401 399
402 void RequestCoordinator::HandleWatchdogTimeout() { 400 void RequestCoordinator::HandleWatchdogTimeout() {
403 StopProcessing(Offliner::REQUEST_COORDINATOR_TIMED_OUT); 401 StopProcessing(Offliner::REQUEST_COORDINATOR_TIMED_OUT);
404 } 402 }
405 403
406 // Returns true if the caller should expect a callback, false otherwise. For 404 // Returns true if the caller should expect a callback, false otherwise. For
407 // instance, this would return false if a request is already in progress. 405 // instance, this would return false if a request is already in progress.
408 bool RequestCoordinator::StartProcessing( 406 bool RequestCoordinator::StartProcessing(
409 const DeviceConditions& device_conditions, 407 const DeviceConditions& device_conditions,
410 const base::Callback<void(bool)>& callback) { 408 const base::Callback<void(bool)>& callback) {
409 return StartProcessingInternal(ProcessingWindowState::SCHEDULED_WINDOW,
410 device_conditions, callback);
411 }
412
413 bool RequestCoordinator::StartProcessingInternal(
414 const ProcessingWindowState processing_state,
415 const DeviceConditions& device_conditions,
416 const base::Callback<void(bool)>& callback) {
411 current_conditions_.reset(new DeviceConditions(device_conditions)); 417 current_conditions_.reset(new DeviceConditions(device_conditions));
412 if (is_starting_ || is_busy_) 418 if (is_starting_ || is_busy_)
413 return false; 419 return false;
414 is_starting_ = true; 420 is_starting_ = true;
421 processing_state_ = processing_state;
422 scheduler_callback_ = callback;
415 423
416 // Mark the time at which we started processing so we can check our time 424 // Mark the time at which we started processing so we can check our time
417 // budget. 425 // budget.
418 operation_start_time_ = base::Time::Now(); 426 operation_start_time_ = base::Time::Now();
419 427
420 is_stopped_ = false;
421 scheduler_callback_ = callback;
422
423 TryNextRequest(); 428 TryNextRequest();
424 429
425 return true; 430 return true;
426 } 431 }
427 432
428 void RequestCoordinator::StartProcessingIfConnected() { 433 void RequestCoordinator::StartImmediatelyIfConnected() {
429 OfflinerImmediateStartStatus immediate_start_status = TryImmediateStart(); 434 OfflinerImmediateStartStatus immediate_start_status = TryImmediateStart();
430 UMA_HISTOGRAM_ENUMERATION( 435 UMA_HISTOGRAM_ENUMERATION(
431 "OfflinePages.Background.ImmediateStartStatus", immediate_start_status, 436 "OfflinePages.Background.ImmediateStartStatus", immediate_start_status,
432 RequestCoordinator::OfflinerImmediateStartStatus::STATUS_COUNT); 437 RequestCoordinator::OfflinerImmediateStartStatus::STATUS_COUNT);
433 } 438 }
434 439
435 RequestCoordinator::OfflinerImmediateStartStatus 440 RequestCoordinator::OfflinerImmediateStartStatus
436 RequestCoordinator::TryImmediateStart() { 441 RequestCoordinator::TryImmediateStart() {
437 // Make sure not already busy processing. 442 // Make sure not already busy processing.
438 if (is_busy_) 443 if (is_busy_)
(...skipping 12 matching lines...) Expand all
451 return OfflinerImmediateStartStatus::WEAK_CONNECTION; 456 return OfflinerImmediateStartStatus::WEAK_CONNECTION;
452 } else if (GetConnectionType() == 457 } else if (GetConnectionType() ==
453 net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE) { 458 net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE) {
454 return OfflinerImmediateStartStatus::NO_CONNECTION; 459 return OfflinerImmediateStartStatus::NO_CONNECTION;
455 } 460 }
456 461
457 // Start processing with manufactured conservative battery conditions 462 // Start processing with manufactured conservative battery conditions
458 // (i.e., assume no battery). 463 // (i.e., assume no battery).
459 // TODO(dougarnett): Obtain actual battery conditions (from Android/Java). 464 // TODO(dougarnett): Obtain actual battery conditions (from Android/Java).
460 DeviceConditions device_conditions(false, 0, GetConnectionType()); 465 DeviceConditions device_conditions(false, 0, GetConnectionType());
461 if (StartProcessing(device_conditions, base::Bind(&EmptySchedulerCallback))) 466 if (StartProcessingInternal(ProcessingWindowState::IMMEDIATE_WINDOW,
467 device_conditions,
468 base::Bind(&EmptySchedulerCallback)))
462 return OfflinerImmediateStartStatus::STARTED; 469 return OfflinerImmediateStartStatus::STARTED;
463 else 470 else
464 return OfflinerImmediateStartStatus::NOT_ACCEPTED; 471 return OfflinerImmediateStartStatus::NOT_ACCEPTED;
465 } 472 }
466 473
467 void RequestCoordinator::TryNextRequest() { 474 void RequestCoordinator::TryNextRequest() {
468 // If there is no time left in the budget, return to the scheduler. 475 // If there is no time left in the budget, return to the scheduler.
469 // We do not remove the pending task that was set up earlier in case 476 // We do not remove the pending task that was set up earlier in case
470 // we run out of time, so the background scheduler will return to us 477 // we run out of time, so the background scheduler will return to us
471 // at the next opportunity to run background tasks. 478 // at the next opportunity to run background tasks.
(...skipping 16 matching lines...) Expand all
488 weak_ptr_factory_.GetWeakPtr()), 495 weak_ptr_factory_.GetWeakPtr()),
489 current_conditions_.get(), 496 current_conditions_.get(),
490 disabled_requests_); 497 disabled_requests_);
491 } 498 }
492 499
493 // Called by the request picker when a request has been picked. 500 // Called by the request picker when a request has been picked.
494 void RequestCoordinator::RequestPicked(const SavePageRequest& request) { 501 void RequestCoordinator::RequestPicked(const SavePageRequest& request) {
495 is_starting_ = false; 502 is_starting_ = false;
496 503
497 // Make sure we were not stopped while picking. 504 // Make sure we were not stopped while picking.
498 if (!is_stopped_) { 505 if (processing_state_ != ProcessingWindowState::STOPPED) {
499 // Send the request on to the offliner. 506 // Send the request on to the offliner.
500 SendRequestToOffliner(request); 507 SendRequestToOffliner(request);
501 } 508 }
502 } 509 }
503 510
504 void RequestCoordinator::RequestNotPicked( 511 void RequestCoordinator::RequestNotPicked(
505 bool non_user_requested_tasks_remaining) { 512 bool non_user_requested_tasks_remaining) {
506 is_starting_ = false; 513 is_starting_ = false;
507 514
508 // Clear the outstanding "safety" task in the scheduler. 515 // Clear the outstanding "safety" task in the scheduler.
509 scheduler_->Unschedule(); 516 scheduler_->Unschedule();
510 517
511 // If disabled tasks remain, post a new safety task for 5 sec from now. 518 // If disabled tasks remain, post a new safety task for 5 sec from now.
512 if (disabled_requests_.size() > 0) { 519 if (disabled_requests_.size() > 0) {
513 scheduler_->BackupSchedule(GetTriggerConditions(kUserRequest), 520 scheduler_->BackupSchedule(GetTriggerConditions(kUserRequest),
514 kDisabledTaskRecheckSeconds); 521 kDisabledTaskRecheckSeconds);
515 } else if (non_user_requested_tasks_remaining) { 522 } else if (non_user_requested_tasks_remaining) {
516 // If we don't have any of those, check for non-user-requested tasks. 523 // If we don't have any of those, check for non-user-requested tasks.
517 scheduler_->Schedule(GetTriggerConditions(!kUserRequest)); 524 scheduler_->Schedule(GetTriggerConditions(!kUserRequest));
518 } 525 }
519 526
520 // Let the scheduler know we are done processing. 527 // Let the scheduler know we are done processing.
521 scheduler_callback_.Run(true); 528 scheduler_callback_.Run(true);
522 } 529 }
523 530
524 void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) { 531 void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) {
525 // Check that offlining didn't get cancelled while performing some async 532 // Check that offlining didn't get cancelled while performing some async
526 // steps. 533 // steps.
527 if (is_stopped_) 534 if (processing_state_ == ProcessingWindowState::STOPPED)
528 return; 535 return;
529 536
530 GetOffliner(); 537 GetOffliner();
531 if (!offliner_) { 538 if (!offliner_) {
532 DVLOG(0) << "Unable to create Offliner. " 539 DVLOG(0) << "Unable to create Offliner. "
533 << "Cannot background offline page."; 540 << "Cannot background offline page.";
534 return; 541 return;
535 } 542 }
536 543
537 DCHECK(!is_busy_); 544 DCHECK(!is_busy_);
538 is_busy_ = true; 545 is_busy_ = true;
539 546
540 // Update the request for this attempt to start it. 547 // Update the request for this attempt to start it.
541 SavePageRequest updated_request(request); 548 SavePageRequest updated_request(request);
542 updated_request.MarkAttemptStarted(base::Time::Now()); 549 updated_request.MarkAttemptStarted(base::Time::Now());
543 queue_->UpdateRequest( 550 queue_->UpdateRequest(
544 updated_request, 551 updated_request,
545 base::Bind(&RequestCoordinator::UpdateRequestCallback, 552 base::Bind(&RequestCoordinator::UpdateRequestCallback,
546 weak_ptr_factory_.GetWeakPtr(), updated_request.client_id())); 553 weak_ptr_factory_.GetWeakPtr(), updated_request.client_id()));
547 active_request_.reset(new SavePageRequest(updated_request)); 554 active_request_.reset(new SavePageRequest(updated_request));
548 555
549 // Start the load and save process in the offliner (Async). 556 // Start the load and save process in the offliner (Async).
550 if (offliner_->LoadAndSave( 557 if (offliner_->LoadAndSave(
551 updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback, 558 updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback,
552 weak_ptr_factory_.GetWeakPtr()))) { 559 weak_ptr_factory_.GetWeakPtr()))) {
553 // Start a watchdog timer to catch pre-renders running too long 560 // Start a watchdog timer to catch pre-renders running too long
554 watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this, 561 // offliner_timeout_ = base::TimeDelta::FromSeconds(
562 // policy_->GetSinglePageTimeLimitInSeconds(is_background_scheduled));
Pete Williamson 2016/10/13 22:58:17 Remove commented out code before checkin
dougarnett 2016/10/14 16:27:01 Done.
563 base::TimeDelta timeout;
564 if (processing_state_ == ProcessingWindowState::SCHEDULED_WINDOW) {
565 timeout = base::TimeDelta::FromSeconds(
566 policy_->GetSinglePageTimeLimitWhenBackgroundScheduledInSeconds());
567 } else {
568 DCHECK(processing_state_ == ProcessingWindowState::IMMEDIATE_WINDOW);
569 timeout = base::TimeDelta::FromSeconds(
570 policy_->GetSinglePageTimeLimitForImmediateLoadInSeconds());
571 }
572 watchdog_timer_.Start(FROM_HERE, timeout, this,
Pete Williamson 2016/10/13 22:58:18 Nice, much less fragile, I like it.
dougarnett 2016/10/14 16:27:01 Acknowledged.
555 &RequestCoordinator::HandleWatchdogTimeout); 573 &RequestCoordinator::HandleWatchdogTimeout);
556 } else { 574 } else {
557 is_busy_ = false; 575 is_busy_ = false;
558 DVLOG(0) << "Unable to start LoadAndSave"; 576 DVLOG(0) << "Unable to start LoadAndSave";
559 StopProcessing(Offliner::PRERENDERING_NOT_STARTED); 577 StopProcessing(Offliner::PRERENDERING_NOT_STARTED);
560 } 578 }
561 } 579 }
562 580
563 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request, 581 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request,
564 Offliner::RequestStatus status) { 582 Offliner::RequestStatus status) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 } 655 }
638 } 656 }
639 657
640 void RequestCoordinator::EnableForOffliner(int64_t request_id) { 658 void RequestCoordinator::EnableForOffliner(int64_t request_id) {
641 // Since the recent tab helper might call multiple times, ignore subsequent 659 // Since the recent tab helper might call multiple times, ignore subsequent
642 // calls for a particular request_id. 660 // calls for a particular request_id.
643 if (disabled_requests_.find(request_id) == disabled_requests_.end()) 661 if (disabled_requests_.find(request_id) == disabled_requests_.end())
644 return; 662 return;
645 disabled_requests_.erase(request_id); 663 disabled_requests_.erase(request_id);
646 // If we are not busy, start processing right away. 664 // If we are not busy, start processing right away.
647 StartProcessingIfConnected(); 665 StartImmediatelyIfConnected();
648 } 666 }
649 667
650 void RequestCoordinator::MarkRequestCompleted(int64_t request_id) { 668 void RequestCoordinator::MarkRequestCompleted(int64_t request_id) {
651 // Since the recent tab helper might call multiple times, ignore subsequent 669 // Since the recent tab helper might call multiple times, ignore subsequent
652 // calls for a particular request_id. 670 // calls for a particular request_id.
653 if (disabled_requests_.find(request_id) == disabled_requests_.end()) 671 if (disabled_requests_.find(request_id) == disabled_requests_.end())
654 return; 672 return;
655 disabled_requests_.erase(request_id); 673 disabled_requests_.erase(request_id);
656 674
657 // Remove the request, but send out SUCCEEDED instead of removed. 675 // Remove the request, but send out SUCCEEDED instead of removed.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 721
704 ClientPolicyController* RequestCoordinator::GetPolicyController() { 722 ClientPolicyController* RequestCoordinator::GetPolicyController() {
705 return policy_controller_.get(); 723 return policy_controller_.get();
706 } 724 }
707 725
708 void RequestCoordinator::Shutdown() { 726 void RequestCoordinator::Shutdown() {
709 network_quality_estimator_ = nullptr; 727 network_quality_estimator_ = nullptr;
710 } 728 }
711 729
712 } // namespace offline_pages 730 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698