1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/engine/syncer_thread.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/rand_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeTicks;
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochusing sessions::SyncSession;
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickusing sessions::SyncSessionSnapshot;
19201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochusing sessions::SyncSourceInfo;
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing syncable::ModelTypePayloadMap;
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing syncable::ModelTypeBitSet;
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing sync_pb::GetUpdatesCallerInfo;
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::DelayProvider::DelayProvider() {}
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::DelayProvider::~DelayProvider() {}
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::WaitInterval::WaitInterval() {}
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::WaitInterval::~WaitInterval() {}
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::SyncSessionJob::SyncSessionJob() {}
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::SyncSessionJob::~SyncSessionJob() {}
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::SyncSessionJob::SyncSessionJob(SyncSessionJobPurpose purpose,
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::TimeTicks start,
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    linked_ptr<sessions::SyncSession> session, bool is_canary_job,
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& nudge_location) : purpose(purpose),
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        scheduled_start(start),
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        session(session),
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        is_canary_job(is_canary_job),
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        nudge_location(nudge_location) {
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTimeDelta SyncerThread::DelayProvider::GetDelay(
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const base::TimeDelta& last_delay) {
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return SyncerThread::GetRecommendedDelay(last_delay);
464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenGetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource(
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    NudgeSource source) {
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  switch (source) {
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case NUDGE_SOURCE_NOTIFICATION:
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return GetUpdatesCallerInfo::NOTIFICATION;
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case NUDGE_SOURCE_LOCAL:
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return GetUpdatesCallerInfo::LOCAL;
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case NUDGE_SOURCE_CONTINUATION:
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION;
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case NUDGE_SOURCE_UNKNOWN:
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return GetUpdatesCallerInfo::UNKNOWN;
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    default:
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NOTREACHED();
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return GetUpdatesCallerInfo::UNKNOWN;
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::WaitInterval::WaitInterval(Mode mode, TimeDelta length)
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : mode(mode), had_nudge(false), length(length) { }
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::SyncerThread(sessions::SyncSessionContext* context,
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           Syncer* syncer)
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : thread_("SyncEngine_SyncerThread"),
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_short_poll_interval_seconds_(
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)),
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_long_poll_interval_seconds_(
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          TimeDelta::FromSeconds(kDefaultLongPollIntervalSeconds)),
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      mode_(NORMAL_MODE),
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      server_connection_ok_(false),
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delay_provider_(new DelayProvider()),
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_(syncer),
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      session_context_(context) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncerThread::~SyncerThread() {
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!thread_.IsRunning());
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::CheckServerConnectionManagerStatus(
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    HttpResponse::ServerConnectionCode code) {
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Server connection changed."
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << "Old mode: " << server_connection_ok_ << " Code: " << code;
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Note, be careful when adding cases here because if the SyncerThread
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // thinks there is no valid connection as determined by this method, it
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // will drop out of *all* forward progress sync loops (it won't poll and it
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // will queue up Talk notifications but not actually call SyncShare) until
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // some external action causes a ServerConnectionManager to broadcast that
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // a valid connection has been re-established.
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (HttpResponse::CONNECTION_UNAVAILABLE == code ||
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      HttpResponse::SYNC_AUTH_ERROR == code) {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_connection_ok_ = false;
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Server connection changed."
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " new mode:" << server_connection_ok_;
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (HttpResponse::SERVER_CONNECTION_OK == code) {
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    server_connection_ok_ = true;
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Server connection changed."
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " new mode:" << server_connection_ok_;
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DoCanaryJob();
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::Start(Mode mode, ModeChangeCallback* callback) {
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << "  Start called from thread "
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << MessageLoop::current()->thread_name();
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thread_.IsRunning()) {
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Starting thread with mode "
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << mode;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!thread_.Start()) {
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NOTREACHED() << "Unable to start SyncerThread.";
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    WatchConnectionManager();
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this, &SyncerThread::SendInitialSnapshot));
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << "  Entering start with mode = "
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << mode;
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this, &SyncerThread::StartImpl, mode, callback));
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::SendInitialSnapshot() {
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<SyncSession> dummy(new SyncSession(session_context_.get(), this,
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSourceInfo(), ModelSafeRoutingInfo(),
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::vector<ModelSafeWorker*>()));
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncEngineEvent event(SyncEngineEvent::STATUS_CHANGED);
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sessions::SyncSessionSnapshot snapshot(dummy->TakeSnapshot());
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  event.snapshot = &snapshot;
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->NotifyListeners(event);
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::WatchConnectionManager() {
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ServerConnectionManager* scm = session_context_->connection_manager();
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CheckServerConnectionManagerStatus(scm->server_status());
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scm->AddListener(this);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::StartImpl(Mode mode, ModeChangeCallback* callback) {
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Doing StartImpl with mode "
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << mode;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(lipalani): This will leak if startimpl is never run. Fix it using a
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // ThreadSafeRefcounted object.
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<ModeChangeCallback> scoped_callback(callback);
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!session_context_->account_name().empty());
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(syncer_.get());
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  mode_ = mode;
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AdjustPolling(NULL);  // Will kick start poll timer if needed.
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (scoped_callback.get())
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_callback->Run();
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We just changed our mode. See if there are any pending jobs that we could
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // execute in the new mode.
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoPendingJobIfPossible(false);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::JobProcessDecision SyncerThread::DecideWhileInWaitInterval(
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const SyncSessionJob& job) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(wait_interval_.get());
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(job.purpose, SyncSessionJob::CLEAR_USER_DATA);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Wait interval mode : "
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << wait_interval_->mode << "Wait interval had nudge : "
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << wait_interval_->had_nudge << "is canary job : "
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << job.is_canary_job;
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.purpose == SyncSessionJob::POLL)
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return DROP;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(job.purpose == SyncSessionJob::NUDGE ||
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      job.purpose == SyncSessionJob::CONFIGURATION);
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (wait_interval_->mode == WaitInterval::THROTTLED)
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return SAVE;
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(wait_interval_->mode, WaitInterval::EXPONENTIAL_BACKOFF);
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.purpose == SyncSessionJob::NUDGE) {
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (mode_ == CONFIGURATION_MODE)
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return SAVE;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // If we already had one nudge then just drop this nudge. We will retry
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // later when the timer runs out.
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return wait_interval_->had_nudge ? DROP : CONTINUE;
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This is a config job.
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return job.is_canary_job ? CONTINUE : SAVE;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncerThread::JobProcessDecision SyncerThread::DecideOnJob(
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const SyncSessionJob& job) {
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.purpose == SyncSessionJob::CLEAR_USER_DATA)
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return CONTINUE;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (wait_interval_.get())
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return DecideWhileInWaitInterval(job);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (mode_ == CONFIGURATION_MODE) {
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (job.purpose == SyncSessionJob::NUDGE)
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return SAVE;
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else if (job.purpose == SyncSessionJob::CONFIGURATION)
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return CONTINUE;
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return DROP;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We are in normal mode.
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(mode_, NORMAL_MODE);
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(job.purpose, SyncSessionJob::CONFIGURATION);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Freshness condition
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.scheduled_start < last_sync_session_end_time_) {
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " Dropping job because of freshness";
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return DROP;
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (server_connection_ok_)
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return CONTINUE;
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " Bad server connection. Using that to decide on job.";
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return job.purpose == SyncSessionJob::NUDGE ? SAVE : DROP;
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::InitOrCoalescePendingJob(const SyncSessionJob& job) {
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(job.purpose != SyncSessionJob::CONFIGURATION);
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (pending_nudge_.get() == NULL) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " Creating a pending nudge job";
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSession* s = job.session.get();
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_ptr<SyncSession> session(new SyncSession(s->context(),
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        s->delegate(), s->source(), s->routing_info(), s->workers()));
2454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob new_job(SyncSessionJob::NUDGE, job.scheduled_start,
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        make_linked_ptr(session.release()), false, job.nudge_location);
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_nudge_.reset(new SyncSessionJob(new_job));
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Coalescing a pending nudge";
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  pending_nudge_->session->Coalesce(*(job.session.get()));
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  pending_nudge_->scheduled_start = job.scheduled_start;
25621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Unfortunately the nudge location cannot be modified. So it stores the
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // location of the first caller.
25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool SyncerThread::ShouldRunJob(const SyncSessionJob& job) {
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  JobProcessDecision decision = DecideOnJob(job);
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Should run job, decision: "
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << decision << " Job purpose " << job.purpose << "mode " << mode_;
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (decision != SAVE)
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return decision == CONTINUE;
26721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(job.purpose == SyncSessionJob::NUDGE || job.purpose ==
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSessionJob::CONFIGURATION);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SaveJob(job);
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::SaveJob(const SyncSessionJob& job) {
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(job.purpose != SyncSessionJob::CLEAR_USER_DATA);
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.purpose == SyncSessionJob::NUDGE) {
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Saving a nudge job";
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    InitOrCoalescePendingJob(job);
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (job.purpose == SyncSessionJob::CONFIGURATION){
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Saving a configuration job";
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(wait_interval_.get());
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(mode_ == CONFIGURATION_MODE);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSession* old = job.session.get();
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSession* s(new SyncSession(session_context_.get(), this,
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        old->source(), old->routing_info(), old->workers()));
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob new_job(job.purpose, TimeTicks::Now(),
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          make_linked_ptr(s), false, job.nudge_location);
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_interval_->pending_configure_job.reset(new SyncSessionJob(new_job));
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } // drop the rest.
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Functor for std::find_if to search by ModelSafeGroup.
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct ModelSafeWorkerGroupIs {
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  explicit ModelSafeWorkerGroupIs(ModelSafeGroup group) : group(group) {}
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool operator()(ModelSafeWorker* w) {
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return group == w->GetModelSafeGroup();
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelSafeGroup group;
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleClearUserData() {
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thread_.IsRunning()) {
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED();
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this, &SyncerThread::ScheduleClearUserDataImpl));
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleNudge(const TimeDelta& delay,
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NudgeSource source, const ModelTypeBitSet& types,
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& nudge_location) {
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thread_.IsRunning()) {
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED();
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Nudge scheduled";
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelTypePayloadMap types_with_payloads =
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::ModelTypePayloadMapFromBitSet(types, std::string());
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this, &SyncerThread::ScheduleNudgeImpl, delay,
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetUpdatesFromNudgeSource(source), types_with_payloads, false,
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      nudge_location));
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleNudgeWithPayloads(const TimeDelta& delay,
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NudgeSource source, const ModelTypePayloadMap& types_with_payloads,
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& nudge_location) {
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thread_.IsRunning()) {
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED();
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Nudge scheduled with payloads";
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this, &SyncerThread::ScheduleNudgeImpl, delay,
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetUpdatesFromNudgeSource(source), types_with_payloads, false,
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      nudge_location));
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleClearUserDataImpl() {
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* session = new SyncSession(session_context_.get(), this,
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSourceInfo(), ModelSafeRoutingInfo(),
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::vector<ModelSafeWorker*>());
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ScheduleSyncSessionJob(TimeDelta::FromSeconds(0),
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSessionJob::CLEAR_USER_DATA, session, FROM_HERE);
35321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
35421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleNudgeImpl(const TimeDelta& delay,
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GetUpdatesCallerInfo::GetUpdatesSource source,
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ModelTypePayloadMap& types_with_payloads,
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool is_canary_job, const tracked_objects::Location& nudge_location) {
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Running Schedule nudge impl";
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Note we currently nudge for all types regardless of the ones incurring
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the nudge.  Doing different would throw off some syncer commands like
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // CleanupDisabledTypes.  We may want to change this in the future.
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSourceInfo info(source, types_with_payloads);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* session(CreateSyncSession(info));
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSessionJob job(SyncSessionJob::NUDGE, TimeTicks::Now() + delay,
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     make_linked_ptr(session), is_canary_job,
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     nudge_location);
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session = NULL;
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!ShouldRunJob(job))
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (pending_nudge_.get()) {
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (IsBackingOff() && delay > TimeDelta::FromSeconds(1)) {
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "SyncerThread(" << this << ")" << " Dropping the nudge because"
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              << "we are in backoff";
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Coalescing pending nudge";
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_nudge_->session->Coalesce(*(job.session.get()));
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!IsBackingOff()) {
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "SyncerThread(" << this << ")" << " Dropping a nudge because"
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              << " we are not in backoff and the job was coalesced";
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      VLOG(1) << "SyncerThread(" << this << ")"
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              << " Rescheduling pending nudge";
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSession* s = pending_nudge_->session.get();
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      job.session.reset(new SyncSession(s->context(), s->delegate(),
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          s->source(), s->routing_info(), s->workers()));
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pending_nudge_.reset();
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(lipalani) - pass the job itself to ScheduleSyncSessionJob.
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ScheduleSyncSessionJob(delay, SyncSessionJob::NUDGE, job.session.release(),
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      nudge_location);
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Helper to extract the routing info and workers corresponding to types in
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// |types| from |registrar|.
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GetModelSafeParamsForTypes(const ModelTypeBitSet& types,
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ModelSafeWorkerRegistrar* registrar, ModelSafeRoutingInfo* routes,
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<ModelSafeWorker*>* workers) {
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelSafeRoutingInfo r_tmp;
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<ModelSafeWorker*> w_tmp;
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar->GetModelSafeRoutingInfo(&r_tmp);
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar->GetWorkers(&w_tmp);
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool passive_group_added = false;
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  typedef std::vector<ModelSafeWorker*>::const_iterator iter;
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = syncable::FIRST_REAL_MODEL_TYPE; i < types.size(); ++i) {
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!types.test(i))
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::ModelType t = syncable::ModelTypeFromInt(i);
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK_EQ(1U, r_tmp.count(t));
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    (*routes)[t] = r_tmp[t];
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    iter it = std::find_if(w_tmp.begin(), w_tmp.end(),
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           ModelSafeWorkerGroupIs(r_tmp[t]));
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (it != w_tmp.end()) {
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      iter it2 = std::find_if(workers->begin(), workers->end(),
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              ModelSafeWorkerGroupIs(r_tmp[t]));
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (it2 == workers->end())
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        workers->push_back(*it);
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (r_tmp[t] == GROUP_PASSIVE)
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        passive_group_added = true;
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        NOTREACHED();
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Always add group passive.
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (passive_group_added == false) {
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    iter it = std::find_if(w_tmp.begin(), w_tmp.end(),
442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           ModelSafeWorkerGroupIs(GROUP_PASSIVE));
443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (it != w_tmp.end())
444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      workers->push_back(*it);
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NOTREACHED();
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleConfig(const ModelTypeBitSet& types) {
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!thread_.IsRunning()) {
452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED();
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Scheduling a config";
457201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ModelSafeRoutingInfo routes;
458201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::vector<ModelSafeWorker*> workers;
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GetModelSafeParamsForTypes(types, session_context_->registrar(),
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             &routes, &workers);
461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this, &SyncerThread::ScheduleConfigImpl, routes, workers,
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetUpdatesCallerInfo::FIRST_UPDATE));
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info,
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<ModelSafeWorker*>& workers,
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " ScheduleConfigImpl...";
473ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(tim): config-specific GetUpdatesCallerInfo value?
474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* session = new SyncSession(session_context_.get(), this,
475ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SyncSourceInfo(source,
476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          syncable::ModelTypePayloadMapFromRoutingInfo(
477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              routing_info, std::string())),
478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      routing_info, workers);
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ScheduleSyncSessionJob(TimeDelta::FromSeconds(0),
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob::CONFIGURATION, session, FROM_HERE);
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleSyncSessionJob(const base::TimeDelta& delay,
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob::SyncSessionJobPurpose purpose,
485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sessions::SyncSession* session,
486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& nudge_location) {
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSessionJob job(purpose, TimeTicks::Now() + delay,
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        make_linked_ptr(session), false, nudge_location);
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (purpose == SyncSessionJob::NUDGE) {
492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Resetting pending_nudge in"
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " ScheduleSyncSessionJob";
494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(!pending_nudge_.get() || pending_nudge_->session.get() == session);
495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_nudge_.reset(new SyncSessionJob(job));
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " Posting job to execute in DoSyncSessionJob. Job purpose "
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << job.purpose;
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(this,
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &SyncerThread::DoSyncSessionJob, job),
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delay.InMilliseconds());
503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::SetSyncerStepsForPurpose(
506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob::SyncSessionJobPurpose purpose,
507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncerStep* start, SyncerStep* end) {
508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *end = SYNCER_END;
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  switch (purpose) {
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SyncSessionJob::CONFIGURATION:
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *start = DOWNLOAD_UPDATES;
512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *end = APPLY_UPDATES;
513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SyncSessionJob::CLEAR_USER_DATA:
515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *start = CLEAR_PRIVATE_DATA;
516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       return;
517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SyncSessionJob::NUDGE:
518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case SyncSessionJob::POLL:
519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *start = SYNCER_BEGIN;
520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    default:
522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NOTREACHED();
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
525201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) {
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!ShouldRunJob(job)) {
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(WARNING) << "Dropping nudge at DoSyncSessionJob, source = "
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        << job.session->source().updates_source;
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job.purpose == SyncSessionJob::NUDGE) {
535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (pending_nudge_.get() == NULL || pending_nudge_->session != job.session)
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;  // Another nudge must have been scheduled in in the meantime.
537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_nudge_.reset();
538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " DoSyncSessionJob. job purpose "
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << job.purpose;
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncerStep begin(SYNCER_BEGIN);
543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncerStep end(SYNCER_END);
544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetSyncerStepsForPurpose(job.purpose, &begin, &end);
545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool has_more_to_sync = true;
547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (ShouldRunJob(job) && has_more_to_sync) {
548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " SyncerThread: Calling SyncShare.";
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Synchronously perform the sync session from this thread.
551ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_->SyncShare(job.session.get(), begin, end);
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    has_more_to_sync = job.session->HasMoreToSync();
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (has_more_to_sync)
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      job.session->ResetTransientState();
555ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " SyncerThread: Done SyncShare looping.";
558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FinishSyncSessionJob(job);
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::UpdateCarryoverSessionState(const SyncSessionJob& old_job) {
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (old_job.purpose == SyncSessionJob::CONFIGURATION) {
563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Whatever types were part of a configuration task will have had updates
564ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // downloaded.  For that reason, we make sure they get recorded in the
565ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // event that they get disabled at a later time.
566ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ModelSafeRoutingInfo r(session_context_->previous_session_routing_info());
567ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!r.empty()) {
568ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ModelSafeRoutingInfo temp_r;
569ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ModelSafeRoutingInfo old_info(old_job.session->routing_info());
570ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::set_union(r.begin(), r.end(), old_info.begin(), old_info.end(),
571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          std::insert_iterator<ModelSafeRoutingInfo>(temp_r, temp_r.begin()));
572ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      session_context_->set_previous_session_routing_info(temp_r);
573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
57472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    session_context_->set_previous_session_routing_info(
576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        old_job.session->routing_info());
57772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
57972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
580ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::FinishSyncSessionJob(const SyncSessionJob& job) {
581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
582ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Update timing information for how often datatypes are triggering nudges.
583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::TimeTicks now = TimeTicks::Now();
584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!last_sync_session_end_time_.is_null()) {
585ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ModelTypePayloadMap::const_iterator iter;
586ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (iter = job.session->source().types.begin();
587ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         iter != job.session->source().types.end();
588ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         ++iter) {
589ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::PostTimeToTypeHistogram(iter->first,
590ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        now - last_sync_session_end_time_);
591201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  last_sync_session_end_time_ = now;
594ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateCarryoverSessionState(job);
595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsSyncingCurrentlySilenced()) {
596ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " We are currently throttled. So not scheduling the next sync.";
598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SaveJob(job);
599ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;  // Nothing to do.
600ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " Updating the next polling time after SyncMain";
604ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ScheduleNextSync(job);
605ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
606ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
607ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::ScheduleNextSync(const SyncSessionJob& old_job) {
608ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
609ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!old_job.session->HasMoreToSync());
610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Note: |num_server_changes_remaining| > 0 here implies that we received a
611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // broken response while trying to download all updates, because the Syncer
612ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // will loop until this value is exhausted. Also, if unsynced_handles exist
613ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // but HasMoreToSync is false, this implies that the Syncer determined no
614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // forward progress was possible at this time (an error, such as an HTTP
615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // 500, is likely to have occurred during commit).
616ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const bool work_to_do =
617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     old_job.session->status_controller()->num_server_changes_remaining() > 0
618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     || old_job.session->status_controller()->unsynced_handles().size() > 0;
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " syncer has work to do: "
620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << work_to_do;
621ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
622ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AdjustPolling(&old_job);
623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(tim): Old impl had special code if notifications disabled. Needed?
625ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!work_to_do) {
626ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Success implies backoff relief.  Note that if this was a "one-off" job
627ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // (i.e. purpose == SyncSessionJob::CLEAR_USER_DATA), if there was
628ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // work_to_do before it ran this wont have changed, as jobs like this don't
629ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // run a full sync cycle.  So we don't need special code here.
630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_interval_.reset();
631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
632ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " Job suceeded so not scheduling more jobs";
633ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
634ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
635ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
636ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (old_job.session->source().updates_source ==
637ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION) {
638ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
639ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " Job failed with source continuation";
640ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We don't seem to have made forward progress. Start or extend backoff.
641ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    HandleConsecutiveContinuationError(old_job);
642ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (IsBackingOff()) {
643ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
644ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " A nudge during backoff failed";
645ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We weren't continuing but we're in backoff; must have been a nudge.
646ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK_EQ(SyncSessionJob::NUDGE, old_job.purpose);
647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(!wait_interval_->had_nudge);
648ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_interval_->had_nudge = true;
649ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_interval_->timer.Reset();
650201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  } else {
651ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")"
652ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            << " Failed. Schedule a job with continuation as source";
653ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We weren't continuing and we aren't in backoff.  Schedule a normal
654ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // continuation.
655ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (old_job.purpose == SyncSessionJob::CONFIGURATION) {
656ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ScheduleConfigImpl(old_job.session->routing_info(),
657ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          old_job.session->workers(),
658ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          GetUpdatesFromNudgeSource(NUDGE_SOURCE_CONTINUATION));
659ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else  {
660ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // For all other purposes(nudge and poll) we schedule a retry nudge.
661ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ScheduleNudgeImpl(TimeDelta::FromSeconds(0),
662ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        GetUpdatesFromNudgeSource(NUDGE_SOURCE_CONTINUATION),
663ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        old_job.session->source().types, false, FROM_HERE);
664201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
665201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
666201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
667201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
668ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::AdjustPolling(const SyncSessionJob* old_job) {
669ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(thread_.IsRunning());
670ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
671ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
672ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimeDelta poll  = (!session_context_->notifications_enabled()) ?
673ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_short_poll_interval_seconds_ :
674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_long_poll_interval_seconds_;
675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool rate_changed = !poll_timer_.IsRunning() ||
676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       poll != poll_timer_.GetCurrentDelay();
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (old_job && old_job->purpose != SyncSessionJob::POLL && !rate_changed)
679ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    poll_timer_.Reset();
680ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
681ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!rate_changed)
682ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
683ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Adjust poll rate.
685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  poll_timer_.Stop();
686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  poll_timer_.Start(poll, this, &SyncerThread::PollTimerCallback);
687201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
688201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
689ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::HandleConsecutiveContinuationError(
690ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const SyncSessionJob& old_job) {
691ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
692ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This if conditions should be compiled out in retail builds.
693ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsBackingOff()) {
694ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(wait_interval_->timer.IsRunning() || old_job.is_canary_job);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
696ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* old = old_job.session.get();
697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* s(new SyncSession(session_context_.get(), this,
698ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      old->source(), old->routing_info(), old->workers()));
699ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TimeDelta length = delay_provider_->GetDelay(
700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      IsBackingOff() ? wait_interval_->length : TimeDelta::FromSeconds(1));
701ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
702ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
703ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " In handle continuation error. Old job purpose is "
704ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << old_job.purpose;
705ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
706ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    << " In Handle continuation error. The time delta(ms) is: "
707ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << length.InMilliseconds();
708ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
709ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This will reset the had_nudge variable as well.
710ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wait_interval_.reset(new WaitInterval(WaitInterval::EXPONENTIAL_BACKOFF,
711ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        length));
712ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (old_job.purpose == SyncSessionJob::CONFIGURATION) {
713ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob job(old_job.purpose, TimeTicks::Now() + length,
714ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        make_linked_ptr(s), false, FROM_HERE);
715ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_interval_->pending_configure_job.reset(new SyncSessionJob(job));
716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
717ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We are not in configuration mode. So wait_interval's pending job
718ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // should be null.
719ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(wait_interval_->pending_configure_job.get() == NULL);
720ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
721ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // TODO(lipalani) - handle clear user data.
722ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    InitOrCoalescePendingJob(old_job);
723ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
724ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wait_interval_->timer.Start(length, this, &SyncerThread::DoCanaryJob);
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
727ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
728ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTimeDelta SyncerThread::GetRecommendedDelay(const TimeDelta& last_delay) {
729ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (last_delay.InSeconds() >= kMaxBackoffSeconds)
730ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return TimeDelta::FromSeconds(kMaxBackoffSeconds);
7313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
733ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int64 backoff_s =
734ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::max(static_cast<int64>(1),
735ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen               last_delay.InSeconds() * kBackoffRandomizationFactor);
7363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Flip a coin to randomize backoff interval by +/- 50%.
7383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int rand_sign = base::RandInt(0, 1) * 2 - 1;
7393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Truncation is adequate for rounding here.
7413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  backoff_s = backoff_s +
742ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      (rand_sign * (last_delay.InSeconds() / kBackoffRandomizationFactor));
7433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Cap the backoff interval.
745ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  backoff_s = std::max(static_cast<int64>(1),
746ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       std::min(backoff_s, kMaxBackoffSeconds));
7473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
748ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return TimeDelta::FromSeconds(backoff_s);
7493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
7503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
751ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::Stop() {
752ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " stop called";
753ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncer_->RequestEarlyExit();  // Safe to call from any thread.
754ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->connection_manager()->RemoveListener(this);
755ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.Stop();
756ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
758ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::DoCanaryJob() {
759ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Do canary job";
760ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoPendingJobIfPossible(true);
761ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
762ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
763ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::DoPendingJobIfPossible(bool is_canary_job) {
764ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSessionJob* job_to_execute = NULL;
765ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (mode_ == CONFIGURATION_MODE && wait_interval_.get()
766ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      && wait_interval_->pending_configure_job.get()) {
767ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Found pending configure job";
768ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    job_to_execute = wait_interval_->pending_configure_job.get();
769ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (mode_ == NORMAL_MODE && pending_nudge_.get()) {
770ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Found pending nudge job";
771ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Pending jobs mostly have time from the past. Reset it so this job
772ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // will get executed.
773ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (pending_nudge_->scheduled_start < TimeTicks::Now())
774ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pending_nudge_->scheduled_start = TimeTicks::Now();
775ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
776ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_ptr<SyncSession> session(CreateSyncSession(
777ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        pending_nudge_->session->source()));
778ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
779ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Also the routing info might have been changed since we cached the
780ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // pending nudge. Update it by coalescing to the latest.
781ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_nudge_->session->Coalesce(*(session.get()));
782ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // The pending nudge would be cleared in the DoSyncSessionJob function.
783ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    job_to_execute = pending_nudge_.get();
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
786ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (job_to_execute != NULL) {
787ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "SyncerThread(" << this << ")" << " Executing pending job";
788ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SyncSessionJob copy = *job_to_execute;
789ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    copy.is_canary_job = is_canary_job;
790ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DoSyncSessionJob(copy);
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
792ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
794ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSyncSession* SyncerThread::CreateSyncSession(const SyncSourceInfo& source) {
795ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelSafeRoutingInfo routes;
796ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<ModelSafeWorker*> workers;
797ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->registrar()->GetModelSafeRoutingInfo(&routes);
798ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->registrar()->GetWorkers(&workers);
799ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSourceInfo info(source);
8003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
801ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* session(new SyncSession(session_context_.get(), this, info,
802ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      routes, workers));
803201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
804ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return session;
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
807ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::PollTimerCallback() {
808ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
809ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelSafeRoutingInfo r;
810ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelTypePayloadMap types_with_payloads =
811ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::ModelTypePayloadMapFromRoutingInfo(r, std::string());
812ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSourceInfo info(GetUpdatesCallerInfo::PERIODIC, types_with_payloads);
813ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncSession* s = CreateSyncSession(info);
814ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ScheduleSyncSessionJob(TimeDelta::FromSeconds(0), SyncSessionJob::POLL, s,
815ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FROM_HERE);
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
818ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::Unthrottle() {
819ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode);
820ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")" << " Unthrottled..";
821ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoCanaryJob();
822ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wait_interval_.reset();
823ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
825ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::Notify(SyncEngineEvent::EventCause cause) {
826ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
827ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->NotifyListeners(SyncEngineEvent(cause));
828ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
830ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool SyncerThread::IsBackingOff() const {
831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return wait_interval_.get() && wait_interval_->mode ==
832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      WaitInterval::EXPONENTIAL_BACKOFF;
833ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::OnSilencedUntil(const base::TimeTicks& silenced_until) {
836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wait_interval_.reset(new WaitInterval(WaitInterval::THROTTLED,
837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        silenced_until - TimeTicks::Now()));
838ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wait_interval_->timer.Start(wait_interval_->length, this,
839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &SyncerThread::Unthrottle);
840ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool SyncerThread::IsSyncingCurrentlySilenced() {
843ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return wait_interval_.get() && wait_interval_->mode ==
844ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      WaitInterval::THROTTLED;
845ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
847ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::OnReceivedShortPollIntervalUpdate(
848ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const base::TimeDelta& new_interval) {
849ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
850ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncer_short_poll_interval_seconds_ = new_interval;
851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
852ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
853ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::OnReceivedLongPollIntervalUpdate(
854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const base::TimeDelta& new_interval) {
855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
856ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncer_long_poll_interval_seconds_ = new_interval;
857ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
858ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::OnShouldStopSyncingPermanently() {
860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "SyncerThread(" << this << ")"
861ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          << " OnShouldStopSyncingPermanently";
862ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncer_->RequestEarlyExit();  // Thread-safe.
863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Notify(SyncEngineEvent::STOP_SYNCING_PERMANENTLY);
864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
865ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
866ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::OnServerConnectionEvent(
867ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ServerConnectionEvent2& event) {
868ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
869ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &SyncerThread::CheckServerConnectionManagerStatus,
870ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      event.connection_code));
871ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
872ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
873ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncerThread::set_notifications_enabled(bool notifications_enabled) {
874ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  session_context_->set_notifications_enabled(notifications_enabled);
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
877ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // browser_sync
878