Index: chrome/browser/sync/engine/syncer_thread2.cc |
diff --git a/chrome/browser/sync/engine/syncer_thread2.cc b/chrome/browser/sync/engine/syncer_thread2.cc |
index 220f5d41700709d6727bdcef0b19de549d2b31cf..639f51857a0a0f9b076fa063d566e7f6125ac6d8 100644 |
--- a/chrome/browser/sync/engine/syncer_thread2.cc |
+++ b/chrome/browser/sync/engine/syncer_thread2.cc |
@@ -78,22 +78,63 @@ SyncerThread::~SyncerThread() { |
DCHECK(!thread_.IsRunning()); |
} |
-void SyncerThread::Start(Mode mode) { |
- if (!thread_.IsRunning() && !thread_.Start()) { |
- NOTREACHED() << "Unable to start SyncerThread."; |
- return; |
+void SyncerThread::CheckServerConnectionManagerStatus( |
+ HttpResponse::ServerConnectionCode code) { |
+ // Note, be careful when adding cases here because if the SyncerThread |
+ // thinks there is no valid connection as determined by this method, it |
+ // will drop out of *all* forward progress sync loops (it won't poll and it |
+ // will queue up Talk notifications but not actually call SyncShare) until |
+ // some external action causes a ServerConnectionManager to broadcast that |
+ // a valid connection has been re-established. |
+ if (HttpResponse::CONNECTION_UNAVAILABLE == code || |
+ HttpResponse::SYNC_AUTH_ERROR == code) { |
+ server_connection_ok_ = false; |
+ } else if (HttpResponse::SERVER_CONNECTION_OK == code) { |
+ server_connection_ok_ = true; |
+ } |
+} |
+ |
+void SyncerThread::Start(Mode mode, ModeChangeCallback* callback) { |
+ if (!thread_.IsRunning()) { |
+ if (!thread_.Start()) { |
+ NOTREACHED() << "Unable to start SyncerThread."; |
+ return; |
+ } |
+ WatchConnectionManager(); |
+ thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &SyncerThread::SendInitialSnapshot)); |
} |
thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
- this, &SyncerThread::StartImpl, mode)); |
+ this, &SyncerThread::StartImpl, mode, make_linked_ptr(callback))); |
+} |
+ |
+void SyncerThread::SendInitialSnapshot() { |
+ DCHECK_EQ(MessageLoop::current(), thread_.message_loop()); |
+ scoped_ptr<SyncSession> dummy(new SyncSession(session_context_.get(), this, |
+ SyncSourceInfo(), ModelSafeRoutingInfo(), |
+ std::vector<ModelSafeWorker*>())); |
+ SyncEngineEvent event(SyncEngineEvent::STATUS_CHANGED); |
+ sessions::SyncSessionSnapshot snapshot(dummy->TakeSnapshot()); |
+ event.snapshot = &snapshot; |
+ session_context_->NotifyListeners(event); |
+} |
+ |
+void SyncerThread::WatchConnectionManager() { |
+ ServerConnectionManager* scm = session_context_->connection_manager(); |
+ CheckServerConnectionManagerStatus(scm->server_status()); |
+ scm->AddListener(this); |
} |
-void SyncerThread::StartImpl(Mode mode) { |
+void SyncerThread::StartImpl(Mode mode, |
+ linked_ptr<ModeChangeCallback> callback) { |
DCHECK_EQ(MessageLoop::current(), thread_.message_loop()); |
DCHECK(!session_context_->account_name().empty()); |
DCHECK(syncer_.get()); |
mode_ = mode; |
AdjustPolling(NULL); // Will kick start poll timer if needed. |
+ if (callback.get()) |
+ callback->Run(); |
} |
bool SyncerThread::ShouldRunJob(SyncSessionJobPurpose purpose, |
@@ -221,6 +262,11 @@ void SyncerThread::ScheduleNudgeImpl(const TimeDelta& delay, |
NudgeSource source, const ModelTypePayloadMap& types_with_payloads) { |
DCHECK_EQ(MessageLoop::current(), thread_.message_loop()); |
TimeTicks rough_start = TimeTicks::Now() + delay; |
+ if (!ShouldRunJob(NUDGE, rough_start)) { |
+ LOG(WARNING) << "Dropping nudge at scheduling time, source = " |
+ << source; |
+ return; |
+ } |
// Note we currently nudge for all types regardless of the ones incurring |
// the nudge. Doing different would throw off some syncer commands like |
@@ -349,6 +395,11 @@ void SyncerThread::SetSyncerStepsForPurpose(SyncSessionJobPurpose purpose, |
void SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) { |
DCHECK_EQ(MessageLoop::current(), thread_.message_loop()); |
+ if (!ShouldRunJob(job.purpose, job.scheduled_start)) { |
+ LOG(WARNING) << "Dropping nudge at DoSyncSessionJob, source = " |
+ << job.session->source().updates_source; |
+ return; |
+ } |
if (job.purpose == NUDGE) { |
DCHECK(pending_nudge_.get()); |
@@ -362,10 +413,8 @@ void SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) { |
SetSyncerStepsForPurpose(job.purpose, &begin, &end); |
bool has_more_to_sync = true; |
- bool did_job = false; |
while (ShouldRunJob(job.purpose, job.scheduled_start) && has_more_to_sync) { |
VLOG(1) << "SyncerThread: Calling SyncShare."; |
- did_job = true; |
// Synchronously perform the sync session from this thread. |
syncer_->SyncShare(job.session.get(), begin, end); |
has_more_to_sync = job.session->HasMoreToSync(); |
@@ -373,8 +422,26 @@ void SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) { |
job.session->ResetTransientState(); |
} |
VLOG(1) << "SyncerThread: Done SyncShare looping."; |
- if (did_job) |
- FinishSyncSessionJob(job); |
+ FinishSyncSessionJob(job); |
+} |
+ |
+void SyncerThread::UpdateCarryoverSessionState(const SyncSessionJob& old_job) { |
+ if (old_job.purpose == CONFIGURATION) { |
+ // Whatever types were part of a configuration task will have had updates |
+ // downloaded. For that reason, we make sure they get recorded in the |
+ // event that they get disabled at a later time. |
+ ModelSafeRoutingInfo r(session_context_->previous_session_routing_info()); |
+ if (!r.empty()) { |
+ ModelSafeRoutingInfo temp_r; |
+ ModelSafeRoutingInfo old_info(old_job.session->routing_info()); |
+ std::set_union(r.begin(), r.end(), old_info.begin(), old_info.end(), |
+ std::insert_iterator<ModelSafeRoutingInfo>(temp_r, temp_r.begin())); |
+ session_context_->set_previous_session_routing_info(temp_r); |
+ } |
+ } else { |
+ session_context_->set_previous_session_routing_info( |
+ old_job.session->routing_info()); |
+ } |
} |
void SyncerThread::FinishSyncSessionJob(const SyncSessionJob& job) { |
@@ -391,6 +458,7 @@ void SyncerThread::FinishSyncSessionJob(const SyncSessionJob& job) { |
} |
} |
last_sync_session_end_time_ = now; |
+ UpdateCarryoverSessionState(job); |
if (IsSyncingCurrentlySilenced()) |
return; // Nothing to do. |
@@ -506,8 +574,8 @@ TimeDelta SyncerThread::GetRecommendedDelay(const TimeDelta& last_delay) { |
void SyncerThread::Stop() { |
syncer_->RequestEarlyExit(); // Safe to call from any thread. |
+ session_context_->connection_manager()->RemoveListener(this); |
thread_.Stop(); |
- Notify(SyncEngineEvent::SYNCER_THREAD_EXITING); |
} |
void SyncerThread::DoCanaryJob() { |
@@ -577,8 +645,10 @@ void SyncerThread::OnShouldStopSyncingPermanently() { |
} |
void SyncerThread::OnServerConnectionEvent( |
- const ServerConnectionEvent& event) { |
- NOTIMPLEMENTED(); |
+ const ServerConnectionEvent2& event) { |
+ thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &SyncerThread::CheckServerConnectionManagerStatus, |
+ event.connection_code)); |
} |
void SyncerThread::set_notifications_enabled(bool notifications_enabled) { |