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

Side by Side Diff: sync/engine/sync_scheduler_impl.cc

Issue 1144443004: Revert of [Sync] Refactoring polling to be reliable. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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
« no previous file with comments | « sync/engine/sync_scheduler_impl.h ('k') | sync/engine/sync_scheduler_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "sync/engine/sync_scheduler_impl.h" 5 #include "sync/engine/sync_scheduler_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cstring> 8 #include <cstring>
9 9
10 #include "base/auto_reset.h"
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
12 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
13 #include "base/location.h" 14 #include "base/location.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
16 #include "sync/engine/backoff_delay_provider.h" 17 #include "sync/engine/backoff_delay_provider.h"
17 #include "sync/engine/syncer.h" 18 #include "sync/engine/syncer.h"
18 #include "sync/protocol/proto_enum_conversions.h" 19 #include "sync/protocol/proto_enum_conversions.h"
19 #include "sync/protocol/sync.pb.h" 20 #include "sync/protocol/sync.pb.h"
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, 149 SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name,
149 BackoffDelayProvider* delay_provider, 150 BackoffDelayProvider* delay_provider,
150 sessions::SyncSessionContext* context, 151 sessions::SyncSessionContext* context,
151 Syncer* syncer) 152 Syncer* syncer)
152 : name_(name), 153 : name_(name),
153 started_(false), 154 started_(false),
154 syncer_short_poll_interval_seconds_( 155 syncer_short_poll_interval_seconds_(
155 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)), 156 TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)),
156 syncer_long_poll_interval_seconds_( 157 syncer_long_poll_interval_seconds_(
157 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)), 158 TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)),
158 mode_(CONFIGURATION_MODE), 159 mode_(NORMAL_MODE),
159 delay_provider_(delay_provider), 160 delay_provider_(delay_provider),
160 syncer_(syncer), 161 syncer_(syncer),
161 session_context_(context), 162 session_context_(context),
162 last_poll_reset_(base::TimeTicks::Now()), 163 no_scheduling_allowed_(false),
164 do_poll_after_credentials_updated_(false),
163 next_sync_session_job_priority_(NORMAL_PRIORITY), 165 next_sync_session_job_priority_(NORMAL_PRIORITY),
164 weak_ptr_factory_(this), 166 weak_ptr_factory_(this),
165 weak_ptr_factory_for_weak_handle_(this) { 167 weak_ptr_factory_for_weak_handle_(this) {
166 weak_handle_this_ = MakeWeakHandle( 168 weak_handle_this_ = MakeWeakHandle(
167 weak_ptr_factory_for_weak_handle_.GetWeakPtr()); 169 weak_ptr_factory_for_weak_handle_.GetWeakPtr());
168 } 170 }
169 171
170 SyncSchedulerImpl::~SyncSchedulerImpl() { 172 SyncSchedulerImpl::~SyncSchedulerImpl() {
171 DCHECK(CalledOnValidThread()); 173 DCHECK(CalledOnValidThread());
172 Stop(); 174 Stop();
(...skipping 25 matching lines...) Expand all
198 // 3. A nudge was saved previously due to not having a valid auth token. 200 // 3. A nudge was saved previously due to not having a valid auth token.
199 // 4. A nudge was scheduled + saved while in configuration mode. 201 // 4. A nudge was scheduled + saved while in configuration mode.
200 // 202 //
201 // In all cases except (2), we want to retry contacting the server. We 203 // In all cases except (2), we want to retry contacting the server. We
202 // call TryCanaryJob to achieve this, and note that nothing -- not even a 204 // call TryCanaryJob to achieve this, and note that nothing -- not even a
203 // canary job -- can bypass a THROTTLED WaitInterval. The only thing that 205 // canary job -- can bypass a THROTTLED WaitInterval. The only thing that
204 // has the authority to do that is the Unthrottle timer. 206 // has the authority to do that is the Unthrottle timer.
205 TryCanaryJob(); 207 TryCanaryJob();
206 } 208 }
207 209
208 void SyncSchedulerImpl::Start(Mode mode, base::Time last_poll_time) { 210 void SyncSchedulerImpl::Start(Mode mode) {
209 DCHECK(CalledOnValidThread()); 211 DCHECK(CalledOnValidThread());
210 std::string thread_name = base::MessageLoop::current()->thread_name(); 212 std::string thread_name = base::MessageLoop::current()->thread_name();
211 if (thread_name.empty()) 213 if (thread_name.empty())
212 thread_name = "<Main thread>"; 214 thread_name = "<Main thread>";
213 SDVLOG(2) << "Start called from thread " 215 SDVLOG(2) << "Start called from thread "
214 << thread_name << " with mode " << GetModeString(mode); 216 << thread_name << " with mode " << GetModeString(mode);
215 if (!started_) { 217 if (!started_) {
216 started_ = true; 218 started_ = true;
217 SendInitialSnapshot(); 219 SendInitialSnapshot();
218 } 220 }
219 221
220 DCHECK(!session_context_->account_name().empty()); 222 DCHECK(!session_context_->account_name().empty());
221 DCHECK(syncer_.get()); 223 DCHECK(syncer_.get());
222 Mode old_mode = mode_; 224 Mode old_mode = mode_;
223 mode_ = mode; 225 mode_ = mode;
224 // Only adjust the poll reset time if it was valid and in the past. 226 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed.
225 if (!last_poll_time.is_null() && last_poll_time < base::Time::Now()) {
226 // Convert from base::Time to base::TimeTicks. The reason we use Time
227 // for persisting is that TimeTicks can stop making forward progress when
228 // the machine is suspended. This implies that on resume the client might
229 // actually have miss the real poll, unless the client is restarted. Fixing
230 // that would require using an AlarmTimer though, which is only supported
231 // on certain platforms.
232 last_poll_reset_ =
233 base::TimeTicks::Now() - (base::Time::Now() - last_poll_time);
234 }
235 227
236 if (old_mode != mode_ && mode_ == NORMAL_MODE) { 228 if (old_mode != mode_ && mode_ == NORMAL_MODE) {
237 // We just got back to normal mode. Let's try to run the work that was 229 // We just got back to normal mode. Let's try to run the work that was
238 // queued up while we were configuring. 230 // queued up while we were configuring.
239 231
240 AdjustPolling(UPDATE_INTERVAL); // Will kick start poll timer if needed.
241
242 // Update our current time before checking IsRetryRequired(). 232 // Update our current time before checking IsRetryRequired().
243 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now()); 233 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now());
244 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY)) { 234 if (nudge_tracker_.IsSyncRequired() && CanRunNudgeJobNow(NORMAL_PRIORITY)) {
245 TrySyncSessionJob(); 235 TrySyncSessionJob();
246 } 236 }
247 } 237 }
248 } 238 }
249 239
250 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() { 240 ModelTypeSet SyncSchedulerImpl::GetEnabledAndUnthrottledTypes() {
251 ModelTypeSet enabled_types = session_context_->GetEnabledTypes(); 241 ModelTypeSet enabled_types = session_context_->GetEnabledTypes();
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 pending_configure_params_.reset(new ConfigurationParams(params)); 299 pending_configure_params_.reset(new ConfigurationParams(params));
310 TrySyncSessionJob(); 300 TrySyncSessionJob();
311 } else { 301 } else {
312 SDVLOG(2) << "No change in routing info, calling ready task directly."; 302 SDVLOG(2) << "No change in routing info, calling ready task directly.";
313 params.ready_task.Run(); 303 params.ready_task.Run();
314 } 304 }
315 } 305 }
316 306
317 bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) { 307 bool SyncSchedulerImpl::CanRunJobNow(JobPriority priority) {
318 DCHECK(CalledOnValidThread()); 308 DCHECK(CalledOnValidThread());
319 if (IsCurrentlyThrottled()) { 309 if (wait_interval_ && wait_interval_->mode == WaitInterval::THROTTLED) {
320 SDVLOG(1) << "Unable to run a job because we're throttled."; 310 SDVLOG(1) << "Unable to run a job because we're throttled.";
321 return false; 311 return false;
322 } 312 }
323 313
324 if (IsBackingOff() && priority != CANARY_PRIORITY) { 314 if (wait_interval_
315 && wait_interval_->mode == WaitInterval::EXPONENTIAL_BACKOFF
316 && priority != CANARY_PRIORITY) {
325 SDVLOG(1) << "Unable to run a job because we're backing off."; 317 SDVLOG(1) << "Unable to run a job because we're backing off.";
326 return false; 318 return false;
327 } 319 }
328 320
329 if (session_context_->connection_manager()->HasInvalidAuthToken()) { 321 if (session_context_->connection_manager()->HasInvalidAuthToken()) {
330 SDVLOG(1) << "Unable to run a job because we have no valid auth token."; 322 SDVLOG(1) << "Unable to run a job because we have no valid auth token.";
331 return false; 323 return false;
332 } 324 }
333 325
334 return true; 326 return true;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 nudge_tracker_.RecordInitialSyncRequired(model_type); 397 nudge_tracker_.RecordInitialSyncRequired(model_type);
406 ScheduleNudgeImpl(TimeDelta::FromSeconds(0), FROM_HERE); 398 ScheduleNudgeImpl(TimeDelta::FromSeconds(0), FROM_HERE);
407 } 399 }
408 400
409 // TODO(zea): Consider adding separate throttling/backoff for datatype 401 // TODO(zea): Consider adding separate throttling/backoff for datatype
410 // refresh requests. 402 // refresh requests.
411 void SyncSchedulerImpl::ScheduleNudgeImpl( 403 void SyncSchedulerImpl::ScheduleNudgeImpl(
412 const TimeDelta& delay, 404 const TimeDelta& delay,
413 const tracked_objects::Location& nudge_location) { 405 const tracked_objects::Location& nudge_location) {
414 DCHECK(CalledOnValidThread()); 406 DCHECK(CalledOnValidThread());
415 CHECK(!syncer_->IsSyncing()); 407
408 if (no_scheduling_allowed_) {
409 NOTREACHED() << "Illegal to schedule job while session in progress.";
410 return;
411 }
416 412
417 if (!started_) { 413 if (!started_) {
418 SDVLOG_LOC(nudge_location, 2) 414 SDVLOG_LOC(nudge_location, 2)
419 << "Dropping nudge, scheduler is not running."; 415 << "Dropping nudge, scheduler is not running.";
420 return; 416 return;
421 } 417 }
422 418
423 SDVLOG_LOC(nudge_location, 2) 419 SDVLOG_LOC(nudge_location, 2)
424 << "In ScheduleNudgeImpl with delay " 420 << "In ScheduleNudgeImpl with delay "
425 << delay.InMilliseconds() << " ms"; 421 << delay.InMilliseconds() << " ms";
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 nudge_tracker_.SetDefaultNudgeDelay(delay_ms); 457 nudge_tracker_.SetDefaultNudgeDelay(delay_ms);
462 } 458 }
463 459
464 void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) { 460 void SyncSchedulerImpl::DoNudgeSyncSessionJob(JobPriority priority) {
465 DCHECK(CalledOnValidThread()); 461 DCHECK(CalledOnValidThread());
466 DCHECK(CanRunNudgeJobNow(priority)); 462 DCHECK(CanRunNudgeJobNow(priority));
467 463
468 DVLOG(2) << "Will run normal mode sync cycle with types " 464 DVLOG(2) << "Will run normal mode sync cycle with types "
469 << ModelTypeSetToString(session_context_->GetEnabledTypes()); 465 << ModelTypeSetToString(session_context_->GetEnabledTypes());
470 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); 466 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
471 bool success = syncer_->NormalSyncShare( 467 bool premature_exit = !syncer_->NormalSyncShare(
472 GetEnabledAndUnthrottledTypes(), &nudge_tracker_, session.get()); 468 GetEnabledAndUnthrottledTypes(), &nudge_tracker_, session.get());
469 AdjustPolling(FORCE_RESET);
470 // Don't run poll job till the next time poll timer fires.
471 do_poll_after_credentials_updated_ = false;
472
473 bool success = !premature_exit
474 && !sessions::HasSyncerError(
475 session->status_controller().model_neutral_state());
473 476
474 if (success) { 477 if (success) {
475 // That cycle took care of any outstanding work we had. 478 // That cycle took care of any outstanding work we had.
476 SDVLOG(2) << "Nudge succeeded."; 479 SDVLOG(2) << "Nudge succeeded.";
477 nudge_tracker_.RecordSuccessfulSyncCycle(); 480 nudge_tracker_.RecordSuccessfulSyncCycle();
478 scheduled_nudge_time_ = base::TimeTicks(); 481 scheduled_nudge_time_ = base::TimeTicks();
479 HandleSuccess();
480 482
481 // If this was a canary, we may need to restart the poll timer (the poll 483 // If we're here, then we successfully reached the server. End all backoff.
482 // timer may have fired while the scheduler was in an error state, ignoring 484 wait_interval_.reset();
483 // the poll). 485 NotifyRetryTime(base::Time());
484 if (!poll_timer_.IsRunning()) {
485 SDVLOG(1) << "Canary succeeded, restarting polling.";
486 AdjustPolling(UPDATE_INTERVAL);
487 }
488 } else { 486 } else {
489 HandleFailure(session->status_controller().model_neutral_state()); 487 HandleFailure(session->status_controller().model_neutral_state());
490 } 488 }
491 } 489 }
492 490
493 void SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) { 491 void SyncSchedulerImpl::DoConfigurationSyncSessionJob(JobPriority priority) {
494 DCHECK(CalledOnValidThread()); 492 DCHECK(CalledOnValidThread());
495 DCHECK_EQ(mode_, CONFIGURATION_MODE); 493 DCHECK_EQ(mode_, CONFIGURATION_MODE);
496 DCHECK(pending_configure_params_ != NULL); 494 DCHECK(pending_configure_params_ != NULL);
497 495
498 if (!CanRunJobNow(priority)) { 496 if (!CanRunJobNow(priority)) {
499 SDVLOG(2) << "Unable to run configure job right now."; 497 SDVLOG(2) << "Unable to run configure job right now.";
500 if (!pending_configure_params_->retry_task.is_null()) { 498 if (!pending_configure_params_->retry_task.is_null()) {
501 pending_configure_params_->retry_task.Run(); 499 pending_configure_params_->retry_task.Run();
502 pending_configure_params_->retry_task.Reset(); 500 pending_configure_params_->retry_task.Reset();
503 } 501 }
504 return; 502 return;
505 } 503 }
506 504
507 SDVLOG(2) << "Will run configure SyncShare with types " 505 SDVLOG(2) << "Will run configure SyncShare with types "
508 << ModelTypeSetToString(session_context_->GetEnabledTypes()); 506 << ModelTypeSetToString(session_context_->GetEnabledTypes());
509 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); 507 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
510 bool success = syncer_->ConfigureSyncShare( 508 bool premature_exit = !syncer_->ConfigureSyncShare(
511 pending_configure_params_->types_to_download, 509 pending_configure_params_->types_to_download,
512 pending_configure_params_->source, 510 pending_configure_params_->source,
513 session.get()); 511 session.get());
512 AdjustPolling(FORCE_RESET);
513 // Don't run poll job till the next time poll timer fires.
514 do_poll_after_credentials_updated_ = false;
515
516 bool success = !premature_exit
517 && !sessions::HasSyncerError(
518 session->status_controller().model_neutral_state());
514 519
515 if (success) { 520 if (success) {
516 SDVLOG(2) << "Configure succeeded."; 521 SDVLOG(2) << "Configure succeeded.";
517 pending_configure_params_->ready_task.Run(); 522 pending_configure_params_->ready_task.Run();
518 pending_configure_params_.reset(); 523 pending_configure_params_.reset();
519 HandleSuccess(); 524
525 // If we're here, then we successfully reached the server. End all backoff.
526 wait_interval_.reset();
527 NotifyRetryTime(base::Time());
520 } else { 528 } else {
521 HandleFailure(session->status_controller().model_neutral_state()); 529 HandleFailure(session->status_controller().model_neutral_state());
522 // Sync cycle might receive response from server that causes scheduler to 530 // Sync cycle might receive response from server that causes scheduler to
523 // stop and draws pending_configure_params_ invalid. 531 // stop and draws pending_configure_params_ invalid.
524 if (started_ && !pending_configure_params_->retry_task.is_null()) { 532 if (started_ && !pending_configure_params_->retry_task.is_null()) {
525 pending_configure_params_->retry_task.Run(); 533 pending_configure_params_->retry_task.Run();
526 pending_configure_params_->retry_task.Reset(); 534 pending_configure_params_->retry_task.Reset();
527 } 535 }
528 } 536 }
529 } 537 }
530 538
531 void SyncSchedulerImpl::HandleSuccess() {
532 // If we're here, then we successfully reached the server. End all backoff.
533 wait_interval_.reset();
534 NotifyRetryTime(base::Time());
535 }
536
537 void SyncSchedulerImpl::HandleFailure( 539 void SyncSchedulerImpl::HandleFailure(
538 const sessions::ModelNeutralState& model_neutral_state) { 540 const sessions::ModelNeutralState& model_neutral_state) {
539 if (IsCurrentlyThrottled()) { 541 if (IsCurrentlyThrottled()) {
540 SDVLOG(2) << "Was throttled during previous sync cycle."; 542 SDVLOG(2) << "Was throttled during previous sync cycle.";
543 RestartWaiting();
541 } else if (!IsBackingOff()) { 544 } else if (!IsBackingOff()) {
542 // Setup our backoff if this is our first such failure. 545 // Setup our backoff if this is our first such failure.
543 TimeDelta length = delay_provider_->GetDelay( 546 TimeDelta length = delay_provider_->GetDelay(
544 delay_provider_->GetInitialDelay(model_neutral_state)); 547 delay_provider_->GetInitialDelay(model_neutral_state));
545 wait_interval_.reset( 548 wait_interval_.reset(
546 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); 549 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
547 SDVLOG(2) << "Sync cycle failed. Will back off for " 550 SDVLOG(2) << "Sync cycle failed. Will back off for "
548 << wait_interval_->length.InMilliseconds() << "ms."; 551 << wait_interval_->length.InMilliseconds() << "ms.";
549 } else { 552 RestartWaiting();
550 // Increase our backoff interval and schedule another retry.
551 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length);
552 wait_interval_.reset(
553 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
554 SDVLOG(2) << "Sync cycle failed. Will back off for "
555 << wait_interval_->length.InMilliseconds() << "ms.";
556 } 553 }
557 RestartWaiting();
558 } 554 }
559 555
560 void SyncSchedulerImpl::DoPollSyncSessionJob() { 556 void SyncSchedulerImpl::DoPollSyncSessionJob() {
557 base::AutoReset<bool> protector(&no_scheduling_allowed_, true);
558
561 SDVLOG(2) << "Polling with types " 559 SDVLOG(2) << "Polling with types "
562 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes()); 560 << ModelTypeSetToString(GetEnabledAndUnthrottledTypes());
563 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this)); 561 scoped_ptr<SyncSession> session(SyncSession::Build(session_context_, this));
564 bool success = syncer_->PollSyncShare( 562 syncer_->PollSyncShare(
565 GetEnabledAndUnthrottledTypes(), 563 GetEnabledAndUnthrottledTypes(),
566 session.get()); 564 session.get());
567 565
568 // Only restart the timer if the poll succeeded. Otherwise rely on normal 566 AdjustPolling(FORCE_RESET);
569 // failure handling to retry with backoff. 567
570 if (success) { 568 if (IsCurrentlyThrottled()) {
571 AdjustPolling(FORCE_RESET); 569 SDVLOG(2) << "Poll request got us throttled.";
572 HandleSuccess(); 570 // The OnSilencedUntil() call set up the WaitInterval for us. All we need
573 } else { 571 // to do is start the timer.
574 HandleFailure(session->status_controller().model_neutral_state()); 572 RestartWaiting();
575 } 573 }
576 } 574 }
577 575
578 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) { 576 void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) {
579 DCHECK(CalledOnValidThread()); 577 DCHECK(CalledOnValidThread());
580 base::TimeTicks now = TimeTicks::Now(); 578 base::TimeTicks now = TimeTicks::Now();
581 // Update timing information for how often datatypes are triggering nudges. 579 // Update timing information for how often datatypes are triggering nudges.
582 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { 580 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
583 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()]; 581 base::TimeTicks previous = last_local_nudges_by_model_type_[iter.Get()];
584 last_local_nudges_by_model_type_[iter.Get()] = now; 582 last_local_nudges_by_model_type_[iter.Get()] = now;
585 if (previous.is_null()) 583 if (previous.is_null())
586 continue; 584 continue;
587 585
588 #define PER_DATA_TYPE_MACRO(type_str) \ 586 #define PER_DATA_TYPE_MACRO(type_str) \
589 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous); 587 SYNC_FREQ_HISTOGRAM("Sync.Freq" type_str, now - previous);
590 SYNC_DATA_TYPE_HISTOGRAM(iter.Get()); 588 SYNC_DATA_TYPE_HISTOGRAM(iter.Get());
591 #undef PER_DATA_TYPE_MACRO 589 #undef PER_DATA_TYPE_MACRO
592 } 590 }
593 } 591 }
594 592
595 TimeDelta SyncSchedulerImpl::GetPollInterval() { 593 TimeDelta SyncSchedulerImpl::GetPollInterval() {
596 return (!session_context_->notifications_enabled() || 594 return (!session_context_->notifications_enabled() ||
597 !session_context_->ShouldFetchUpdatesBeforeCommit()) ? 595 !session_context_->ShouldFetchUpdatesBeforeCommit()) ?
598 syncer_short_poll_interval_seconds_ : 596 syncer_short_poll_interval_seconds_ :
599 syncer_long_poll_interval_seconds_; 597 syncer_long_poll_interval_seconds_;
600 } 598 }
601 599
602 void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) { 600 void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) {
603 DCHECK(CalledOnValidThread()); 601 DCHECK(CalledOnValidThread());
604 if (!started_) 602
603 TimeDelta poll = GetPollInterval();
604 bool rate_changed = !poll_timer_.IsRunning() ||
605 poll != poll_timer_.GetCurrentDelay();
606
607 if (type == FORCE_RESET) {
608 last_poll_reset_ = base::TimeTicks::Now();
609 if (!rate_changed)
610 poll_timer_.Reset();
611 }
612
613 if (!rate_changed)
605 return; 614 return;
606 615
607 TimeDelta poll_interval = GetPollInterval(); 616 // Adjust poll rate.
608 TimeDelta poll_delay = poll_interval; 617 poll_timer_.Stop();
609 const TimeTicks now = TimeTicks::Now(); 618 poll_timer_.Start(FROM_HERE, poll, this,
610
611 if (type == UPDATE_INTERVAL) {
612 // Override the delay based on the last successful poll time (if it was
613 // set).
614 TimeTicks new_poll_time;
615 if (!last_poll_reset_.is_null())
616 new_poll_time = poll_interval + last_poll_reset_;
617 else
618 new_poll_time = poll_interval + now;
619 poll_delay = new_poll_time - now;
620 if (poll_delay < TimeDelta()) {
621 // The desired poll time was in the past, so trigger a poll now (the timer
622 /// will post the task asynchronously, so re-entrancy isn't an issue).
623 poll_delay = TimeDelta();
624 }
625 } else {
626 // Otherwise just restart the timer.
627 DCHECK_EQ(FORCE_RESET, type);
628 DCHECK_EQ(GetPollInterval(), poll_delay);
629 last_poll_reset_ = now;
630 }
631
632 SDVLOG(1) << "Updating polling delay to " << poll_delay.InMinutes()
633 << " minutes.";
634
635 // Adjust poll rate. Start will reset the timer if it was already running.
636 poll_timer_.Start(FROM_HERE, poll_delay, this,
637 &SyncSchedulerImpl::PollTimerCallback); 619 &SyncSchedulerImpl::PollTimerCallback);
638 } 620 }
639 621
640 void SyncSchedulerImpl::RestartWaiting() { 622 void SyncSchedulerImpl::RestartWaiting() {
641 CHECK(wait_interval_.get()); 623 CHECK(wait_interval_.get());
642 DCHECK(wait_interval_->length >= TimeDelta::FromSeconds(0)); 624 DCHECK(wait_interval_->length >= TimeDelta::FromSeconds(0));
643 NotifyRetryTime(base::Time::Now() + wait_interval_->length); 625 NotifyRetryTime(base::Time::Now() + wait_interval_->length);
644 SDVLOG(2) << "Starting WaitInterval timer of length " 626 SDVLOG(2) << "Starting WaitInterval timer of length "
645 << wait_interval_->length.InMilliseconds() << "ms."; 627 << wait_interval_->length.InMilliseconds() << "ms.";
646 if (wait_interval_->mode == WaitInterval::THROTTLED) { 628 if (wait_interval_->mode == WaitInterval::THROTTLED) {
(...skipping 23 matching lines...) Expand all
670 pending_wakeup_timer_.Stop(); 652 pending_wakeup_timer_.Stop();
671 pending_configure_params_.reset(); 653 pending_configure_params_.reset();
672 if (started_) 654 if (started_)
673 started_ = false; 655 started_ = false;
674 } 656 }
675 657
676 // This is the only place where we invoke DoSyncSessionJob with canary 658 // This is the only place where we invoke DoSyncSessionJob with canary
677 // privileges. Everyone else should use NORMAL_PRIORITY. 659 // privileges. Everyone else should use NORMAL_PRIORITY.
678 void SyncSchedulerImpl::TryCanaryJob() { 660 void SyncSchedulerImpl::TryCanaryJob() {
679 next_sync_session_job_priority_ = CANARY_PRIORITY; 661 next_sync_session_job_priority_ = CANARY_PRIORITY;
680 SDVLOG(2) << "Attempting canary job";
681 TrySyncSessionJob(); 662 TrySyncSessionJob();
682 } 663 }
683 664
684 void SyncSchedulerImpl::TrySyncSessionJob() { 665 void SyncSchedulerImpl::TrySyncSessionJob() {
685 // Post call to TrySyncSessionJobImpl on current thread. Later request for 666 // Post call to TrySyncSessionJobImpl on current thread. Later request for
686 // access token will be here. 667 // access token will be here.
687 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 668 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
688 &SyncSchedulerImpl::TrySyncSessionJobImpl, 669 &SyncSchedulerImpl::TrySyncSessionJobImpl,
689 weak_ptr_factory_.GetWeakPtr())); 670 weak_ptr_factory_.GetWeakPtr()));
690 } 671 }
691 672
692 void SyncSchedulerImpl::TrySyncSessionJobImpl() { 673 void SyncSchedulerImpl::TrySyncSessionJobImpl() {
693 JobPriority priority = next_sync_session_job_priority_; 674 JobPriority priority = next_sync_session_job_priority_;
694 next_sync_session_job_priority_ = NORMAL_PRIORITY; 675 next_sync_session_job_priority_ = NORMAL_PRIORITY;
695 676
696 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now()); 677 nudge_tracker_.SetSyncCycleStartTime(base::TimeTicks::Now());
697 678
698 DCHECK(CalledOnValidThread()); 679 DCHECK(CalledOnValidThread());
699 if (mode_ == CONFIGURATION_MODE) { 680 if (mode_ == CONFIGURATION_MODE) {
700 if (pending_configure_params_) { 681 if (pending_configure_params_) {
701 SDVLOG(2) << "Found pending configure job"; 682 SDVLOG(2) << "Found pending configure job";
702 DoConfigurationSyncSessionJob(priority); 683 DoConfigurationSyncSessionJob(priority);
703 } 684 }
704 } else if (CanRunNudgeJobNow(priority)) { 685 } else if (CanRunNudgeJobNow(priority)) {
705 if (nudge_tracker_.IsSyncRequired()) { 686 if (nudge_tracker_.IsSyncRequired()) {
706 SDVLOG(2) << "Found pending nudge job"; 687 SDVLOG(2) << "Found pending nudge job";
707 DoNudgeSyncSessionJob(priority); 688 DoNudgeSyncSessionJob(priority);
708 } else if (((base::TimeTicks::Now() - last_poll_reset_) >= 689 } else if (do_poll_after_credentials_updated_ ||
709 GetPollInterval())) { 690 ((base::TimeTicks::Now() - last_poll_reset_) >= GetPollInterval())) {
710 SDVLOG(2) << "Found pending poll";
711 DoPollSyncSessionJob(); 691 DoPollSyncSessionJob();
692 // Poll timer fires infrequently. Usually by this time access token is
693 // already expired and poll job will fail with auth error. Set flag to
694 // retry poll once ProfileSyncService gets new access token, TryCanaryJob
695 // will be called after access token is retrieved.
696 if (HttpResponse::SYNC_AUTH_ERROR ==
697 session_context_->connection_manager()->server_status()) {
698 do_poll_after_credentials_updated_ = true;
699 }
712 } 700 }
713 } else { 701 }
714 // We must be in an error state. Transitioning out of each of these 702
715 // error states should trigger a canary job. 703 if (priority == CANARY_PRIORITY) {
716 DCHECK(IsCurrentlyThrottled() || IsBackingOff() || 704 // If this is canary job then whatever result was don't run poll job till
717 session_context_->connection_manager()->HasInvalidAuthToken()); 705 // the next time poll timer fires.
706 do_poll_after_credentials_updated_ = false;
718 } 707 }
719 708
720 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) { 709 if (IsBackingOff() && !pending_wakeup_timer_.IsRunning()) {
721 // If we succeeded, our wait interval would have been cleared. If it hasn't 710 // If we succeeded, our wait interval would have been cleared. If it hasn't
722 // been cleared, then we should increase our backoff interval and schedule 711 // been cleared, then we should increase our backoff interval and schedule
723 // another retry. 712 // another retry.
724 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length); 713 TimeDelta length = delay_provider_->GetDelay(wait_interval_->length);
725 wait_interval_.reset( 714 wait_interval_.reset(
726 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length)); 715 new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF, length));
727 SDVLOG(2) << "Sync cycle failed. Will back off for " 716 SDVLOG(2) << "Sync cycle failed. Will back off for "
728 << wait_interval_->length.InMilliseconds() << "ms."; 717 << wait_interval_->length.InMilliseconds() << "ms.";
729 RestartWaiting(); 718 RestartWaiting();
730 } 719 }
731 } 720 }
732 721
733 void SyncSchedulerImpl::PollTimerCallback() { 722 void SyncSchedulerImpl::PollTimerCallback() {
734 DCHECK(CalledOnValidThread()); 723 DCHECK(CalledOnValidThread());
735 CHECK(!syncer_->IsSyncing()); 724 if (no_scheduling_allowed_) {
725 // The no_scheduling_allowed_ flag is set by a function-scoped AutoReset in
726 // functions that are called only on the sync thread. This function is also
727 // called only on the sync thread, and only when it is posted by an expiring
728 // timer. If we find that no_scheduling_allowed_ is set here, then
729 // something is very wrong. Maybe someone mistakenly called us directly, or
730 // mishandled the book-keeping for no_scheduling_allowed_.
731 NOTREACHED() << "Illegal to schedule job while session in progress.";
732 return;
733 }
736 734
737 TrySyncSessionJob(); 735 TrySyncSessionJob();
738 } 736 }
739 737
740 void SyncSchedulerImpl::RetryTimerCallback() { 738 void SyncSchedulerImpl::RetryTimerCallback() {
741 TrySyncSessionJob(); 739 TrySyncSessionJob();
742 } 740 }
743 741
744 void SyncSchedulerImpl::Unthrottle() { 742 void SyncSchedulerImpl::Unthrottle() {
745 DCHECK(CalledOnValidThread()); 743 DCHECK(CalledOnValidThread());
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 throttle_duration)); 819 throttle_duration));
822 NotifyRetryTime(base::Time::Now() + wait_interval_->length); 820 NotifyRetryTime(base::Time::Now() + wait_interval_->length);
823 NotifyThrottledTypesChanged(ModelTypeSet::All()); 821 NotifyThrottledTypesChanged(ModelTypeSet::All());
824 } 822 }
825 823
826 void SyncSchedulerImpl::OnTypesThrottled( 824 void SyncSchedulerImpl::OnTypesThrottled(
827 ModelTypeSet types, 825 ModelTypeSet types,
828 const base::TimeDelta& throttle_duration) { 826 const base::TimeDelta& throttle_duration) {
829 base::TimeTicks now = base::TimeTicks::Now(); 827 base::TimeTicks now = base::TimeTicks::Now();
830 828
831 SDVLOG(1) << "Throttling " << ModelTypeSetToString(types) << " for "
832 << throttle_duration.InMinutes() << " minutes.";
833
834 nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now); 829 nudge_tracker_.SetTypesThrottledUntil(types, throttle_duration, now);
835 base::TimeDelta time_until_next_unthrottle = 830 base::TimeDelta time_until_next_unthrottle =
836 nudge_tracker_.GetTimeUntilNextUnthrottle(now); 831 nudge_tracker_.GetTimeUntilNextUnthrottle(now);
837 type_unthrottle_timer_.Start( 832 type_unthrottle_timer_.Start(
838 FROM_HERE, 833 FROM_HERE,
839 time_until_next_unthrottle, 834 time_until_next_unthrottle,
840 base::Bind(&SyncSchedulerImpl::TypeUnthrottle, 835 base::Bind(&SyncSchedulerImpl::TypeUnthrottle,
841 weak_ptr_factory_.GetWeakPtr(), 836 weak_ptr_factory_.GetWeakPtr(),
842 now + time_until_next_unthrottle)); 837 now + time_until_next_unthrottle));
843 NotifyThrottledTypesChanged(nudge_tracker_.GetThrottledTypes()); 838 NotifyThrottledTypesChanged(nudge_tracker_.GetThrottledTypes());
844 } 839 }
845 840
846 bool SyncSchedulerImpl::IsCurrentlyThrottled() { 841 bool SyncSchedulerImpl::IsCurrentlyThrottled() {
847 DCHECK(CalledOnValidThread()); 842 DCHECK(CalledOnValidThread());
848 return wait_interval_.get() && wait_interval_->mode == 843 return wait_interval_.get() && wait_interval_->mode ==
849 WaitInterval::THROTTLED; 844 WaitInterval::THROTTLED;
850 } 845 }
851 846
852 void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate( 847 void SyncSchedulerImpl::OnReceivedShortPollIntervalUpdate(
853 const base::TimeDelta& new_interval) { 848 const base::TimeDelta& new_interval) {
854 DCHECK(CalledOnValidThread()); 849 DCHECK(CalledOnValidThread());
855 if (new_interval == syncer_short_poll_interval_seconds_)
856 return;
857 SDVLOG(1) << "Updating short poll interval to " << new_interval.InMinutes()
858 << " minutes.";
859 syncer_short_poll_interval_seconds_ = new_interval; 850 syncer_short_poll_interval_seconds_ = new_interval;
860 AdjustPolling(UPDATE_INTERVAL);
861 } 851 }
862 852
863 void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate( 853 void SyncSchedulerImpl::OnReceivedLongPollIntervalUpdate(
864 const base::TimeDelta& new_interval) { 854 const base::TimeDelta& new_interval) {
865 DCHECK(CalledOnValidThread()); 855 DCHECK(CalledOnValidThread());
866 if (new_interval == syncer_long_poll_interval_seconds_)
867 return;
868 SDVLOG(1) << "Updating long poll interval to " << new_interval.InMinutes()
869 << " minutes.";
870 syncer_long_poll_interval_seconds_ = new_interval; 856 syncer_long_poll_interval_seconds_ = new_interval;
871 AdjustPolling(UPDATE_INTERVAL);
872 } 857 }
873 858
874 void SyncSchedulerImpl::OnReceivedCustomNudgeDelays( 859 void SyncSchedulerImpl::OnReceivedCustomNudgeDelays(
875 const std::map<ModelType, base::TimeDelta>& nudge_delays) { 860 const std::map<ModelType, base::TimeDelta>& nudge_delays) {
876 DCHECK(CalledOnValidThread()); 861 DCHECK(CalledOnValidThread());
877 nudge_tracker_.OnReceivedCustomNudgeDelays(nudge_delays); 862 nudge_tracker_.OnReceivedCustomNudgeDelays(nudge_delays);
878 } 863 }
879 864
880 void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) { 865 void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) {
881 if (size > 0) 866 if (size > 0)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 907
923 #undef SDVLOG_LOC 908 #undef SDVLOG_LOC
924 909
925 #undef SDVLOG 910 #undef SDVLOG
926 911
927 #undef SLOG 912 #undef SLOG
928 913
929 #undef ENUM_CASE 914 #undef ENUM_CASE
930 915
931 } // namespace syncer 916 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/sync_scheduler_impl.h ('k') | sync/engine/sync_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698