summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 09:51:46 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-14 09:51:46 +0000
commit2aa4ec16d252d37c12fa6d8a187350a906808a7a (patch)
tree74310906434c1854629fa377e4ee74f247f3cf0e
parent1ba346dd63e728e508be1e84aa234c53c7d6e1d3 (diff)
downloadchromium_src-2aa4ec16d252d37c12fa6d8a187350a906808a7a.zip
chromium_src-2aa4ec16d252d37c12fa6d8a187350a906808a7a.tar.gz
chromium_src-2aa4ec16d252d37c12fa6d8a187350a906808a7a.tar.bz2
[Sync] Combine sync thread and sync core thread.
Rename SyncerThread to SyncerScheduler and its owned thread; it is now a (mostly) non-thread-safe class which schedules events on the message loop it was created on. Rename core_thread_ in SyncBackendHost to sync_thread_ (and associated variables). BUG=79174 TEST= Review URL: http://codereview.chromium.org/6995097 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@88976 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync/engine/sync_scheduler.cc (renamed from chrome/browser/sync/engine/syncer_thread.cc)329
-rw-r--r--chrome/browser/sync/engine/sync_scheduler.h (renamed from chrome/browser/sync/engine/syncer_thread.h)105
-rw-r--r--chrome/browser/sync/engine/sync_scheduler_unittest.cc (renamed from chrome/browser/sync/engine/syncer_thread_unittest.cc)773
-rw-r--r--chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc233
-rw-r--r--chrome/browser/sync/engine/syncapi.cc174
-rw-r--r--chrome/browser/sync/engine/syncapi.h11
-rw-r--r--chrome/browser/sync/engine/syncer_thread_whitebox_unittest.cc232
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc75
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h53
-rw-r--r--chrome/browser/sync/test_profile_sync_service.cc2
-rw-r--r--chrome/chrome.gyp4
-rw-r--r--chrome/chrome_tests.gypi4
12 files changed, 1084 insertions, 911 deletions
diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/sync_scheduler.cc
index 44c528c..22fd7f6 100644
--- a/chrome/browser/sync/engine/syncer_thread.cc
+++ b/chrome/browser/sync/engine/sync_scheduler.cc
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/sync/engine/syncer_thread.h"
+#include "chrome/browser/sync/engine/sync_scheduler.h"
#include <algorithm>
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
#include "base/rand_util.h"
#include "chrome/browser/sync/engine/syncer.h"
@@ -21,16 +23,16 @@ using syncable::ModelTypePayloadMap;
using syncable::ModelTypeBitSet;
using sync_pb::GetUpdatesCallerInfo;
-SyncerThread::DelayProvider::DelayProvider() {}
-SyncerThread::DelayProvider::~DelayProvider() {}
+SyncScheduler::DelayProvider::DelayProvider() {}
+SyncScheduler::DelayProvider::~DelayProvider() {}
-SyncerThread::WaitInterval::WaitInterval() {}
-SyncerThread::WaitInterval::~WaitInterval() {}
+SyncScheduler::WaitInterval::WaitInterval() {}
+SyncScheduler::WaitInterval::~WaitInterval() {}
-SyncerThread::SyncSessionJob::SyncSessionJob() {}
-SyncerThread::SyncSessionJob::~SyncSessionJob() {}
+SyncScheduler::SyncSessionJob::SyncSessionJob() {}
+SyncScheduler::SyncSessionJob::~SyncSessionJob() {}
-SyncerThread::SyncSessionJob::SyncSessionJob(SyncSessionJobPurpose purpose,
+SyncScheduler::SyncSessionJob::SyncSessionJob(SyncSessionJobPurpose purpose,
base::TimeTicks start,
linked_ptr<sessions::SyncSession> session, bool is_canary_job,
const tracked_objects::Location& nudge_location) : purpose(purpose),
@@ -40,9 +42,9 @@ SyncerThread::SyncSessionJob::SyncSessionJob(SyncSessionJobPurpose purpose,
nudge_location(nudge_location) {
}
-TimeDelta SyncerThread::DelayProvider::GetDelay(
+TimeDelta SyncScheduler::DelayProvider::GetDelay(
const base::TimeDelta& last_delay) {
- return SyncerThread::GetRecommendedDelay(last_delay);
+ return SyncScheduler::GetRecommendedDelay(last_delay);
}
GetUpdatesCallerInfo::GetUpdatesSource GetUpdatesFromNudgeSource(
@@ -76,18 +78,20 @@ GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
return GetUpdatesCallerInfo::UNKNOWN;
}
-SyncerThread::WaitInterval::WaitInterval(Mode mode, TimeDelta length)
+SyncScheduler::WaitInterval::WaitInterval(Mode mode, TimeDelta length)
: mode(mode), had_nudge(false), length(length) { }
// Helper macro to log with the syncer thread name; useful when there
// are multiple syncer threads involved.
#define SVLOG(verbose_level) VLOG(verbose_level) << name_ << ": "
-SyncerThread::SyncerThread(const std::string& name,
- sessions::SyncSessionContext* context,
- Syncer* syncer)
- : name_(name),
- thread_("SyncEngine_SyncerThread"),
+SyncScheduler::SyncScheduler(const std::string& name,
+ sessions::SyncSessionContext* context,
+ Syncer* syncer)
+ : method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ name_(name),
+ sync_loop_(MessageLoop::current()),
+ started_(false),
syncer_short_poll_interval_seconds_(
TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds)),
syncer_long_poll_interval_seconds_(
@@ -97,17 +101,20 @@ SyncerThread::SyncerThread(const std::string& name,
delay_provider_(new DelayProvider()),
syncer_(syncer),
session_context_(context) {
+ DCHECK(sync_loop_);
}
-SyncerThread::~SyncerThread() {
- DCHECK(!thread_.IsRunning());
+SyncScheduler::~SyncScheduler() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ Stop();
}
-void SyncerThread::CheckServerConnectionManagerStatus(
+void SyncScheduler::CheckServerConnectionManagerStatus(
HttpResponse::ServerConnectionCode code) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
bool old_server_connection_ok = server_connection_ok_;
- // Note, be careful when adding cases here because if the SyncerThread
+ // Note, be careful when adding cases here because if the SyncScheduler
// 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
@@ -128,27 +135,29 @@ void SyncerThread::CheckServerConnectionManagerStatus(
}
}
-void SyncerThread::Start(Mode mode, ModeChangeCallback* callback) {
+void SyncScheduler::Start(Mode mode, ModeChangeCallback* callback) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Start called from thread "
<< MessageLoop::current()->thread_name() << " with mode "
<< mode;
- if (!thread_.IsRunning()) {
- SVLOG(2) << "Starting thread with mode " << mode;
- if (!thread_.Start()) {
- NOTREACHED() << "Unable to start SyncerThread.";
- return;
- }
+ if (!started_) {
WatchConnectionManager();
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::SendInitialSnapshot));
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::SendInitialSnapshot));
}
-
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::StartImpl, mode, callback));
+ started_ = true;
+ // TODO(sync): This will leak if StartImpl is never run. Fix this.
+ // Might be easiest to just use base::Callback.
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::StartImpl, mode, callback));
}
-void SyncerThread::SendInitialSnapshot() {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::SendInitialSnapshot() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
scoped_ptr<SyncSession> dummy(new SyncSession(session_context_.get(), this,
SyncSourceInfo(), ModelSafeRoutingInfo(),
std::vector<ModelSafeWorker*>()));
@@ -158,19 +167,23 @@ void SyncerThread::SendInitialSnapshot() {
session_context_->NotifyListeners(event);
}
-void SyncerThread::WatchConnectionManager() {
+void SyncScheduler::WatchConnectionManager() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
ServerConnectionManager* scm = session_context_->connection_manager();
- CheckServerConnectionManagerStatus(scm->server_status());
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::CheckServerConnectionManagerStatus,
+ scm->server_status()));
scm->AddListener(this);
}
-void SyncerThread::StartImpl(Mode mode, ModeChangeCallback* callback) {
+void SyncScheduler::StartImpl(Mode mode, ModeChangeCallback* callback) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Doing StartImpl with mode " << mode;
- // TODO(lipalani): This will leak if startimpl is never run. Fix it using a
- // ThreadSafeRefcounted object.
scoped_ptr<ModeChangeCallback> scoped_callback(callback);
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(!session_context_->account_name().empty());
DCHECK(syncer_.get());
mode_ = mode;
@@ -183,9 +196,9 @@ void SyncerThread::StartImpl(Mode mode, ModeChangeCallback* callback) {
DoPendingJobIfPossible(false);
}
-SyncerThread::JobProcessDecision SyncerThread::DecideWhileInWaitInterval(
+SyncScheduler::JobProcessDecision SyncScheduler::DecideWhileInWaitInterval(
const SyncSessionJob& job) {
-
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(wait_interval_.get());
DCHECK_NE(job.purpose, SyncSessionJob::CLEAR_USER_DATA);
@@ -215,8 +228,9 @@ SyncerThread::JobProcessDecision SyncerThread::DecideWhileInWaitInterval(
return job.is_canary_job ? CONTINUE : SAVE;
}
-SyncerThread::JobProcessDecision SyncerThread::DecideOnJob(
+SyncScheduler::JobProcessDecision SyncScheduler::DecideOnJob(
const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
if (job.purpose == SyncSessionJob::CLEAR_USER_DATA)
return CONTINUE;
@@ -249,7 +263,8 @@ SyncerThread::JobProcessDecision SyncerThread::DecideOnJob(
return job.purpose == SyncSessionJob::NUDGE ? SAVE : DROP;
}
-void SyncerThread::InitOrCoalescePendingJob(const SyncSessionJob& job) {
+void SyncScheduler::InitOrCoalescePendingJob(const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(job.purpose != SyncSessionJob::CONFIGURATION);
if (pending_nudge_.get() == NULL) {
SVLOG(2) << "Creating a pending nudge job";
@@ -272,7 +287,8 @@ void SyncerThread::InitOrCoalescePendingJob(const SyncSessionJob& job) {
// location of the first caller.
}
-bool SyncerThread::ShouldRunJob(const SyncSessionJob& job) {
+bool SyncScheduler::ShouldRunJob(const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
JobProcessDecision decision = DecideOnJob(job);
SVLOG(2) << "Should run job, decision: "
<< decision << ", job purpose " << job.purpose
@@ -287,7 +303,8 @@ bool SyncerThread::ShouldRunJob(const SyncSessionJob& job) {
return false;
}
-void SyncerThread::SaveJob(const SyncSessionJob& job) {
+void SyncScheduler::SaveJob(const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(job.purpose != SyncSessionJob::CLEAR_USER_DATA);
if (job.purpose == SyncSessionJob::NUDGE) {
SVLOG(2) << "Saving a nudge job";
@@ -301,7 +318,7 @@ void SyncerThread::SaveJob(const SyncSessionJob& job) {
SyncSession* s(new SyncSession(session_context_.get(), this,
old->source(), old->routing_info(), old->workers()));
SyncSessionJob new_job(job.purpose, TimeTicks::Now(),
- make_linked_ptr(s), false, job.nudge_location);
+ make_linked_ptr(s), false, job.nudge_location);
wait_interval_->pending_configure_job.reset(new SyncSessionJob(new_job));
} // drop the rest.
}
@@ -315,52 +332,46 @@ struct ModelSafeWorkerGroupIs {
ModelSafeGroup group;
};
-void SyncerThread::ScheduleClearUserData() {
- if (!thread_.IsRunning()) {
- NOTREACHED();
- return;
- }
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::ScheduleClearUserDataImpl));
+void SyncScheduler::ScheduleClearUserData() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::ScheduleClearUserDataImpl));
}
-void SyncerThread::ScheduleNudge(const TimeDelta& delay,
+void SyncScheduler::ScheduleNudge(const TimeDelta& delay,
NudgeSource source, const ModelTypeBitSet& types,
const tracked_objects::Location& nudge_location) {
- if (!thread_.IsRunning()) {
- LOG(INFO) << "Dropping nudge because thread is not running.";
- NOTREACHED();
- return;
- }
-
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Nudge scheduled (source=" << source << ")";
ModelTypePayloadMap types_with_payloads =
syncable::ModelTypePayloadMapFromBitSet(types, std::string());
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::ScheduleNudgeImpl, delay,
- GetUpdatesFromNudgeSource(source), types_with_payloads, false,
- nudge_location));
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::ScheduleNudgeImpl, delay,
+ GetUpdatesFromNudgeSource(source), types_with_payloads, false,
+ nudge_location));
}
-void SyncerThread::ScheduleNudgeWithPayloads(const TimeDelta& delay,
+void SyncScheduler::ScheduleNudgeWithPayloads(const TimeDelta& delay,
NudgeSource source, const ModelTypePayloadMap& types_with_payloads,
const tracked_objects::Location& nudge_location) {
- if (!thread_.IsRunning()) {
- NOTREACHED();
- return;
- }
-
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Nudge scheduled with payloads (source=" << source << ")";
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::ScheduleNudgeImpl, delay,
- GetUpdatesFromNudgeSource(source), types_with_payloads, false,
- nudge_location));
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::ScheduleNudgeImpl, delay,
+ GetUpdatesFromNudgeSource(source), types_with_payloads, false,
+ nudge_location));
}
-void SyncerThread::ScheduleClearUserDataImpl() {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::ScheduleClearUserDataImpl() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SyncSession* session = new SyncSession(session_context_.get(), this,
SyncSourceInfo(), ModelSafeRoutingInfo(),
std::vector<ModelSafeWorker*>());
@@ -368,11 +379,11 @@ void SyncerThread::ScheduleClearUserDataImpl() {
SyncSessionJob::CLEAR_USER_DATA, session, FROM_HERE);
}
-void SyncerThread::ScheduleNudgeImpl(const TimeDelta& delay,
+void SyncScheduler::ScheduleNudgeImpl(const TimeDelta& delay,
GetUpdatesCallerInfo::GetUpdatesSource source,
const ModelTypePayloadMap& types_with_payloads,
bool is_canary_job, const tracked_objects::Location& nudge_location) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Running Schedule nudge impl (source=" << source << ")";
// Note we currently nudge for all types regardless of the ones incurring
@@ -461,29 +472,27 @@ void GetModelSafeParamsForTypes(const ModelTypeBitSet& types,
}
}
-void SyncerThread::ScheduleConfig(const ModelTypeBitSet& types,
- sync_api::ConfigureReason reason) {
- if (!thread_.IsRunning()) {
- LOG(INFO) << "ScheduleConfig failed because thread is not running.";
- NOTREACHED();
- return;
- }
-
+void SyncScheduler::ScheduleConfig(const ModelTypeBitSet& types,
+ sync_api::ConfigureReason reason) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Scheduling a config";
ModelSafeRoutingInfo routes;
std::vector<ModelSafeWorker*> workers;
GetModelSafeParamsForTypes(types, session_context_->registrar(),
&routes, &workers);
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SyncerThread::ScheduleConfigImpl, routes, workers,
- GetSourceFromReason(reason)));
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::ScheduleConfigImpl, routes, workers,
+ GetSourceFromReason(reason)));
}
-void SyncerThread::ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info,
+void SyncScheduler::ScheduleConfigImpl(
+ const ModelSafeRoutingInfo& routing_info,
const std::vector<ModelSafeWorker*>& workers,
const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "ScheduleConfigImpl...";
// TODO(tim): config-specific GetUpdatesCallerInfo value?
@@ -496,14 +505,14 @@ void SyncerThread::ScheduleConfigImpl(const ModelSafeRoutingInfo& routing_info,
SyncSessionJob::CONFIGURATION, session, FROM_HERE);
}
-void SyncerThread::ScheduleSyncSessionJob(const base::TimeDelta& delay,
+void SyncScheduler::ScheduleSyncSessionJob(const base::TimeDelta& delay,
SyncSessionJob::SyncSessionJobPurpose purpose,
sessions::SyncSession* session,
const tracked_objects::Location& nudge_location) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SyncSessionJob job(purpose, TimeTicks::Now() + delay,
- make_linked_ptr(session), false, nudge_location);
+ make_linked_ptr(session), false, nudge_location);
if (purpose == SyncSessionJob::NUDGE) {
SVLOG(2) << "Resetting pending_nudge in ScheduleSyncSessionJob";
DCHECK(!pending_nudge_.get() || pending_nudge_->session.get() == session);
@@ -511,14 +520,17 @@ void SyncerThread::ScheduleSyncSessionJob(const base::TimeDelta& delay,
}
SVLOG(2) << "Posting job to execute in DoSyncSessionJob. Job purpose "
<< job.purpose;
- MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(this,
- &SyncerThread::DoSyncSessionJob, job),
+ sync_loop_->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::DoSyncSessionJob, job),
delay.InMilliseconds());
}
-void SyncerThread::SetSyncerStepsForPurpose(
+void SyncScheduler::SetSyncerStepsForPurpose(
SyncSessionJob::SyncSessionJobPurpose purpose,
SyncerStep* start, SyncerStep* end) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
*end = SYNCER_END;
switch (purpose) {
case SyncSessionJob::CONFIGURATION:
@@ -537,8 +549,8 @@ void SyncerThread::SetSyncerStepsForPurpose(
}
}
-void SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::DoSyncSessionJob(const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
if (!ShouldRunJob(job)) {
LOG(WARNING) << "Not executing job at DoSyncSessionJob, purpose = "
<< job.purpose << " source = "
@@ -580,7 +592,9 @@ void SyncerThread::DoSyncSessionJob(const SyncSessionJob& job) {
FinishSyncSessionJob(job);
}
-void SyncerThread::UpdateCarryoverSessionState(const SyncSessionJob& old_job) {
+void SyncScheduler::UpdateCarryoverSessionState(
+ const SyncSessionJob& old_job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
if (old_job.purpose == SyncSessionJob::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
@@ -599,8 +613,8 @@ void SyncerThread::UpdateCarryoverSessionState(const SyncSessionJob& old_job) {
}
}
-void SyncerThread::FinishSyncSessionJob(const SyncSessionJob& job) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::FinishSyncSessionJob(const SyncSessionJob& job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
// Update timing information for how often datatypes are triggering nudges.
base::TimeTicks now = TimeTicks::Now();
if (!last_sync_session_end_time_.is_null()) {
@@ -624,8 +638,8 @@ void SyncerThread::FinishSyncSessionJob(const SyncSessionJob& job) {
ScheduleNextSync(job);
}
-void SyncerThread::ScheduleNextSync(const SyncSessionJob& old_job) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::ScheduleNextSync(const SyncSessionJob& old_job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(!old_job.session->HasMoreToSync());
// Note: |num_server_changes_remaining| > 0 here implies that we received a
// broken response while trying to download all updates, because the Syncer
@@ -667,7 +681,8 @@ void SyncerThread::ScheduleNextSync(const SyncSessionJob& old_job) {
DCHECK_EQ(SyncSessionJob::NUDGE, old_job.purpose);
DCHECK(!wait_interval_->had_nudge);
wait_interval_->had_nudge = true;
- wait_interval_->timer.Reset();
+ // Resume waiting.
+ RestartWaiting();
} else {
SVLOG(2) << "Failed. Schedule a job with continuation as source";
// We weren't continuing and we aren't in backoff. Schedule a normal
@@ -685,9 +700,8 @@ void SyncerThread::ScheduleNextSync(const SyncSessionJob& old_job) {
}
}
-void SyncerThread::AdjustPolling(const SyncSessionJob* old_job) {
- DCHECK(thread_.IsRunning());
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::AdjustPolling(const SyncSessionJob* old_job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
TimeDelta poll = (!session_context_->notifications_enabled()) ?
syncer_short_poll_interval_seconds_ :
@@ -703,15 +717,23 @@ void SyncerThread::AdjustPolling(const SyncSessionJob* old_job) {
// Adjust poll rate.
poll_timer_.Stop();
- poll_timer_.Start(poll, this, &SyncerThread::PollTimerCallback);
+ poll_timer_.Start(poll, this, &SyncScheduler::PollTimerCallback);
+}
+
+void SyncScheduler::RestartWaiting() {
+ CHECK(wait_interval_.get());
+ wait_interval_->timer.Stop();
+ wait_interval_->timer.Start(wait_interval_->length,
+ this, &SyncScheduler::DoCanaryJob);
}
-void SyncerThread::HandleConsecutiveContinuationError(
+void SyncScheduler::HandleConsecutiveContinuationError(
const SyncSessionJob& old_job) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
- // This if conditions should be compiled out in retail builds.
- if (IsBackingOff()) {
- DCHECK(wait_interval_->timer.IsRunning() || old_job.is_canary_job);
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ if (DCHECK_IS_ON()) {
+ if (IsBackingOff()) {
+ DCHECK(wait_interval_->timer.IsRunning() || old_job.is_canary_job);
+ }
}
TimeDelta length = delay_provider_->GetDelay(
@@ -739,11 +761,11 @@ void SyncerThread::HandleConsecutiveContinuationError(
// TODO(lipalani) - handle clear user data.
InitOrCoalescePendingJob(old_job);
}
- wait_interval_->timer.Start(length, this, &SyncerThread::DoCanaryJob);
+ RestartWaiting();
}
// static
-TimeDelta SyncerThread::GetRecommendedDelay(const TimeDelta& last_delay) {
+TimeDelta SyncScheduler::GetRecommendedDelay(const TimeDelta& last_delay) {
if (last_delay.InSeconds() >= kMaxBackoffSeconds)
return TimeDelta::FromSeconds(kMaxBackoffSeconds);
@@ -766,19 +788,30 @@ TimeDelta SyncerThread::GetRecommendedDelay(const TimeDelta& last_delay) {
return TimeDelta::FromSeconds(backoff_s);
}
-void SyncerThread::Stop() {
- SVLOG(2) << "stop called";
+void SyncScheduler::RequestEarlyExit() {
syncer_->RequestEarlyExit(); // Safe to call from any thread.
- session_context_->connection_manager()->RemoveListener(this);
- thread_.Stop();
}
-void SyncerThread::DoCanaryJob() {
+void SyncScheduler::Stop() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ SVLOG(2) << "Stop called";
+ method_factory_.RevokeAll();
+ wait_interval_.reset();
+ poll_timer_.Stop();
+ if (started_) {
+ session_context_->connection_manager()->RemoveListener(this);
+ started_ = false;
+ }
+}
+
+void SyncScheduler::DoCanaryJob() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "Do canary job";
DoPendingJobIfPossible(true);
}
-void SyncerThread::DoPendingJobIfPossible(bool is_canary_job) {
+void SyncScheduler::DoPendingJobIfPossible(bool is_canary_job) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SyncSessionJob* job_to_execute = NULL;
if (mode_ == CONFIGURATION_MODE && wait_interval_.get()
&& wait_interval_->pending_configure_job.get()) {
@@ -809,7 +842,8 @@ void SyncerThread::DoPendingJobIfPossible(bool is_canary_job) {
}
}
-SyncSession* SyncerThread::CreateSyncSession(const SyncSourceInfo& source) {
+SyncSession* SyncScheduler::CreateSyncSession(const SyncSourceInfo& source) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
ModelSafeRoutingInfo routes;
std::vector<ModelSafeWorker*> workers;
session_context_->registrar()->GetModelSafeRoutingInfo(&routes);
@@ -822,8 +856,8 @@ SyncSession* SyncerThread::CreateSyncSession(const SyncSourceInfo& source) {
return session;
}
-void SyncerThread::PollTimerCallback() {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::PollTimerCallback() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
ModelSafeRoutingInfo r;
ModelTypePayloadMap types_with_payloads =
syncable::ModelTypePayloadMapFromRoutingInfo(r, std::string());
@@ -833,61 +867,70 @@ void SyncerThread::PollTimerCallback() {
FROM_HERE);
}
-void SyncerThread::Unthrottle() {
+void SyncScheduler::Unthrottle() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK_EQ(WaitInterval::THROTTLED, wait_interval_->mode);
SVLOG(2) << "Unthrottled.";
DoCanaryJob();
wait_interval_.reset();
}
-void SyncerThread::Notify(SyncEngineEvent::EventCause cause) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+void SyncScheduler::Notify(SyncEngineEvent::EventCause cause) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
session_context_->NotifyListeners(SyncEngineEvent(cause));
}
-bool SyncerThread::IsBackingOff() const {
+bool SyncScheduler::IsBackingOff() const {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
return wait_interval_.get() && wait_interval_->mode ==
WaitInterval::EXPONENTIAL_BACKOFF;
}
-void SyncerThread::OnSilencedUntil(const base::TimeTicks& silenced_until) {
+void SyncScheduler::OnSilencedUntil(const base::TimeTicks& silenced_until) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
wait_interval_.reset(new WaitInterval(WaitInterval::THROTTLED,
silenced_until - TimeTicks::Now()));
wait_interval_->timer.Start(wait_interval_->length, this,
- &SyncerThread::Unthrottle);
+ &SyncScheduler::Unthrottle);
}
-bool SyncerThread::IsSyncingCurrentlySilenced() {
+bool SyncScheduler::IsSyncingCurrentlySilenced() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
return wait_interval_.get() && wait_interval_->mode ==
WaitInterval::THROTTLED;
}
-void SyncerThread::OnReceivedShortPollIntervalUpdate(
+void SyncScheduler::OnReceivedShortPollIntervalUpdate(
const base::TimeDelta& new_interval) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
syncer_short_poll_interval_seconds_ = new_interval;
}
-void SyncerThread::OnReceivedLongPollIntervalUpdate(
+void SyncScheduler::OnReceivedLongPollIntervalUpdate(
const base::TimeDelta& new_interval) {
- DCHECK_EQ(MessageLoop::current(), thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
syncer_long_poll_interval_seconds_ = new_interval;
}
-void SyncerThread::OnShouldStopSyncingPermanently() {
+void SyncScheduler::OnShouldStopSyncingPermanently() {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
SVLOG(2) << "OnShouldStopSyncingPermanently";
syncer_->RequestEarlyExit(); // Thread-safe.
Notify(SyncEngineEvent::STOP_SYNCING_PERMANENTLY);
}
-void SyncerThread::OnServerConnectionEvent(
+void SyncScheduler::OnServerConnectionEvent(
const ServerConnectionEvent& event) {
- thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &SyncerThread::CheckServerConnectionManagerStatus,
- event.connection_code));
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
+ sync_loop_->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SyncScheduler::CheckServerConnectionManagerStatus,
+ event.connection_code));
}
-void SyncerThread::set_notifications_enabled(bool notifications_enabled) {
+void SyncScheduler::set_notifications_enabled(bool notifications_enabled) {
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
session_context_->set_notifications_enabled(notifications_enabled);
}
diff --git a/chrome/browser/sync/engine/syncer_thread.h b/chrome/browser/sync/engine/sync_scheduler.h
index be7d028..df0521f 100644
--- a/chrome/browser/sync/engine/syncer_thread.h
+++ b/chrome/browser/sync/engine/sync_scheduler.h
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// A class to run the syncer on a thread.
-#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD_H_
-#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD_H_
+// A class to schedule syncer tasks intelligently.
+#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
+#define CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
#pragma once
#include <string>
#include "base/callback.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/task.h"
-#include "base/threading/thread.h"
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/sync/engine/configure_reason.h"
@@ -27,12 +27,14 @@
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/sessions/sync_session_context.h"
+class MessageLoop;
+
namespace browser_sync {
struct ServerConnectionEvent;
-class SyncerThread : public sessions::SyncSession::Delegate,
- public ServerConnectionEventListener {
+class SyncScheduler : public sessions::SyncSession::Delegate,
+ public ServerConnectionEventListener {
public:
enum Mode {
// In this mode, the thread only performs configuration tasks. This is
@@ -45,29 +47,35 @@ class SyncerThread : public sessions::SyncSession::Delegate,
NORMAL_MODE,
};
+ // All methods of SyncScheduler must be called on the same thread
+ // (except for RequestEarlyExit()).
+
// |name| is a display string to identify the syncer thread. Takes
// |ownership of both |context| and |syncer|.
- SyncerThread(const std::string& name,
- sessions::SyncSessionContext* context, Syncer* syncer);
- virtual ~SyncerThread();
+ SyncScheduler(const std::string& name,
+ sessions::SyncSessionContext* context, Syncer* syncer);
+
+ // Calls Stop().
+ virtual ~SyncScheduler();
typedef Callback0::Type ModeChangeCallback;
- // Change the mode of operation.
- // We don't use a lock when changing modes, so we won't cause currently
- // scheduled jobs to adhere to the new mode. We could protect it, but it
- // doesn't buy very much as a) a session could already be in progress and it
- // will continue no matter what, b) the scheduled sessions already contain
- // all their required state and won't be affected by potential change at
- // higher levels (i.e. the registrar), and c) we service tasks FIFO, so once
- // the mode changes all future jobs will be run against the updated mode.
- // If supplied, |callback| will be invoked when the mode has been
- // changed to |mode| *from the SyncerThread*, and not from the caller
- // thread.
+ // Start the scheduler with the given mode. If the scheduler is
+ // already started, switch to the given mode, although some
+ // scheduled tasks from the old mode may still run. If non-NULL,
+ // |callback| will be invoked when the mode has been changed to
+ // |mode|. Takes ownership of |callback|.
void Start(Mode mode, ModeChangeCallback* callback);
- // Joins on the thread as soon as possible (currently running session
- // completes).
+ // Request that any running syncer task stop as soon as possible.
+ // This function can be called from any thread. Stop must still be
+ // called to stop future schedule tasks.
+ //
+ // TODO(akalin): This function is awkward. Find a better way to let
+ // the UI thread stop the syncer thread.
+ void RequestEarlyExit();
+
+ // Cancel all scheduled tasks. Can be called even if already stopped.
void Stop();
// The meat and potatoes.
@@ -145,25 +153,25 @@ class SyncerThread : public sessions::SyncSession::Delegate,
// that came in.
tracked_objects::Location nudge_location;
};
- friend class SyncerThreadTest;
- friend class SyncerThreadWhiteboxTest;
+ friend class SyncSchedulerTest;
+ friend class SyncSchedulerWhiteboxTest;
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
DropNudgeWhileExponentialBackOff);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest, SaveNudge);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest, ContinueNudge);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest, DropPoll);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest, ContinuePoll);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest, ContinueConfiguration);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge);
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueNudge);
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, DropPoll);
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinuePoll);
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, ContinueConfiguration);
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
SaveConfigurationWhileThrottled);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
SaveNudgeWhileThrottled);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
ContinueClearUserDataUnderAllCircumstances);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
ContinueCanaryJobConfig);
- FRIEND_TEST_ALL_PREFIXES(SyncerThreadWhiteboxTest,
+ FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
ContinueNudgeWhileExponentialBackOff);
// A component used to get time delays associated with exponential backoff.
@@ -196,7 +204,7 @@ class SyncerThread : public sessions::SyncSession::Delegate,
// interval and mode == EXPONENTIAL_BACKOFF.
bool had_nudge;
base::TimeDelta length;
- base::OneShotTimer<SyncerThread> timer;
+ base::OneShotTimer<SyncScheduler> timer;
// Configure jobs are saved only when backing off or throttling. So we
// expose the pointer here.
@@ -228,6 +236,9 @@ class SyncerThread : public sessions::SyncSession::Delegate,
// Helper to configure polling intervals. Used by Start and ScheduleNextSync.
void AdjustPolling(const SyncSessionJob* old_job);
+ // Helper to restart waiting with |wait_interval_|'s timer.
+ void RestartWaiting();
+
// Helper to ScheduleNextSync in case of consecutive sync errors.
void HandleConsecutiveContinuationError(const SyncSessionJob& old_job);
@@ -302,9 +313,17 @@ class SyncerThread : public sessions::SyncSession::Delegate,
// the client starts up and does not need to perform an initial sync.
void SendInitialSnapshot();
+ ScopedRunnableMethodFactory<SyncScheduler> method_factory_;
+
+ // Used for logging.
const std::string name_;
- base::Thread thread_;
+ // The message loop this object is on. Almost all methods have to
+ // be called on this thread.
+ MessageLoop* const sync_loop_;
+
+ // Set in Start(), unset in Stop().
+ bool started_;
// Modifiable versions of kDefaultLongPollIntervalSeconds which can be
// updated by the server.
@@ -312,9 +331,9 @@ class SyncerThread : public sessions::SyncSession::Delegate,
base::TimeDelta syncer_long_poll_interval_seconds_;
// Periodic timer for polling. See AdjustPolling.
- base::RepeatingTimer<SyncerThread> poll_timer_;
+ base::RepeatingTimer<SyncScheduler> poll_timer_;
- // The mode of operation. We don't use a lock, see Start(...) comment.
+ // The mode of operation.
Mode mode_;
// TODO(tim): Bug 26339. This needs to track more than just time I think,
@@ -337,13 +356,9 @@ class SyncerThread : public sessions::SyncSession::Delegate,
scoped_ptr<sessions::SyncSessionContext> session_context_;
- DISALLOW_COPY_AND_ASSIGN(SyncerThread);
+ DISALLOW_COPY_AND_ASSIGN(SyncScheduler);
};
} // namespace browser_sync
-// The SyncerThread manages its own internal thread and thus outlives it. We
-// don't need refcounting for posting tasks to this internal thread.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(browser_sync::SyncerThread);
-
-#endif // CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD_H_
+#endif // CHROME_BROWSER_SYNC_ENGINE_SYNC_SCHEDULER_H_
diff --git a/chrome/browser/sync/engine/syncer_thread_unittest.cc b/chrome/browser/sync/engine/sync_scheduler_unittest.cc
index a2ce04e..d7310d5 100644
--- a/chrome/browser/sync/engine/syncer_thread_unittest.cc
+++ b/chrome/browser/sync/engine/sync_scheduler_unittest.cc
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/synchronization/waitable_event.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_callback_factory.h"
+#include "base/message_loop.h"
+#include "base/task.h"
#include "base/test/test_timeouts.h"
#include "chrome/browser/sync/engine/mock_model_safe_workers.h"
#include "chrome/browser/sync/engine/configure_reason.h"
+#include "chrome/browser/sync/engine/sync_scheduler.h"
#include "chrome/browser/sync/engine/syncer.h"
-#include "chrome/browser/sync/engine/syncer_thread.h"
#include "chrome/browser/sync/sessions/test_util.h"
#include "chrome/test/sync/engine/mock_connection_manager.h"
#include "chrome/test/sync/engine/test_directory_setter_upper.h"
@@ -44,11 +49,37 @@ struct SyncShareRecords {
std::vector<linked_ptr<SyncSessionSnapshot> > snapshots;
};
+void QuitLoopNow() {
+ // We use QuitNow() instead of Quit() as the latter may get stalled
+ // indefinitely in the presence of repeated timers with low delays
+ // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
+ // delay of 5ms] run under TSAN on the trybots).
+ MessageLoop::current()->QuitNow();
+}
+
+void RunLoop() {
+ MessageLoop::current()->Run();
+}
+
+void PumpLoop() {
+ // Do it this way instead of RunAllPending to pump loop exactly once
+ // (necessary in the presence of timers; see comment in
+ // QuitLoopNow).
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
+ RunLoop();
+}
+
// Convenient to use in tests wishing to analyze SyncShare calls over time.
static const size_t kMinNumSamples = 5;
-class SyncerThreadTest : public testing::Test {
+class SyncSchedulerTest : public testing::Test {
public:
- class MockDelayProvider : public SyncerThread::DelayProvider {
+ SyncSchedulerTest()
+ : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ context_(NULL),
+ syncer_(NULL),
+ delay_(NULL) {}
+
+ class MockDelayProvider : public SyncScheduler::DelayProvider {
public:
MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
};
@@ -70,11 +101,11 @@ class SyncerThreadTest : public testing::Test {
registrar_.get(), std::vector<SyncEngineEventListener*>());
context_->set_notifications_enabled(true);
context_->set_account_name("Test");
- syncer_thread_.reset(
- new SyncerThread("TestSyncerThread", context_, syncer_));
+ scheduler_.reset(
+ new SyncScheduler("TestSyncScheduler", context_, syncer_));
}
- SyncerThread* syncer_thread() { return syncer_thread_.get(); }
+ SyncScheduler* scheduler() { return scheduler_.get(); }
MockSyncer* syncer() { return syncer_; }
MockDelayProvider* delay() { return delay_; }
MockConnectionManager* connection() { return connection_.get(); }
@@ -84,7 +115,9 @@ class SyncerThreadTest : public testing::Test {
}
virtual void TearDown() {
- syncer_thread()->Stop();
+ PumpLoop();
+ scheduler_.reset();
+ PumpLoop();
syncdb_.TearDown();
}
@@ -101,16 +134,32 @@ class SyncerThreadTest : public testing::Test {
}
}
- bool GetBackoffAndResetTest(base::WaitableEvent* done) {
+ void DoQuitLoopNow() {
+ QuitLoopNow();
+ }
+
+ void StartSyncScheduler(SyncScheduler::Mode mode) {
+ scheduler()->Start(
+ mode,
+ callback_factory_.NewCallback(&SyncSchedulerTest::DoQuitLoopNow));
+ }
+
+ bool GetBackoffAndResetTest() {
syncable::ModelTypeBitSet nudge_types;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types,
- FROM_HERE);
- done->TimedWait(timeout());
- TearDown();
- done->Reset();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
+ RunLoop();
+
+ bool backing_off = scheduler()->IsBackingOff();
+ scheduler()->Stop();
+ syncdb_.TearDown();
+
Mock::VerifyAndClearExpectations(syncer());
- bool backing_off = syncer_thread()->IsBackingOff();
+
+ TearDown();
SetUp();
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
@@ -120,26 +169,7 @@ class SyncerThreadTest : public testing::Test {
void UseMockDelayProvider() {
delay_ = new MockDelayProvider();
- syncer_thread_->delay_provider_.reset(delay_);
- }
-
- void PostSignalTask(base::WaitableEvent* done) {
- syncer_thread_->thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableFunction(&SyncerThreadTest::SignalWaitableEvent, done));
- }
-
- void FlushLastTask(base::WaitableEvent* done) {
- PostSignalTask(done);
- done->TimedWait(timeout());
- done->Reset();
- }
-
- static void SignalWaitableEvent(base::WaitableEvent* event) {
- event->Signal();
- }
-
- static void QuitMessageLoop() {
- MessageLoop::current()->Quit();
+ scheduler_->delay_provider_.reset(delay_);
}
// Compare a ModelTypeBitSet to a ModelTypePayloadMap, ignoring
@@ -161,7 +191,9 @@ class SyncerThreadTest : public testing::Test {
SyncSessionContext* context() { return context_; }
private:
- scoped_ptr<SyncerThread> syncer_thread_;
+ base::ScopedCallbackFactory<SyncSchedulerTest> callback_factory_;
+ MessageLoop message_loop_;
+ scoped_ptr<SyncScheduler> scheduler_;
scoped_ptr<MockConnectionManager> connection_;
SyncSessionContext* context_;
MockSyncer* syncer_;
@@ -170,62 +202,72 @@ class SyncerThreadTest : public testing::Test {
MockDirectorySetterUpper syncdb_;
};
-bool RecordSyncShareImpl(SyncSession* s, SyncShareRecords* record,
- size_t signal_after) {
+void RecordSyncShareImpl(SyncSession* s, SyncShareRecords* record) {
record->times.push_back(TimeTicks::Now());
record->snapshots.push_back(make_linked_ptr(new SyncSessionSnapshot(
s->TakeSnapshot())));
- return record->times.size() >= signal_after;
}
-ACTION_P4(RecordSyncShareAndPostSignal, record, signal_after, test, event) {
- if (RecordSyncShareImpl(arg0, record, signal_after) && event)
- test->PostSignalTask(event);
+ACTION_P(RecordSyncShare, record) {
+ RecordSyncShareImpl(arg0, record);
+ QuitLoopNow();
}
-ACTION_P3(RecordSyncShare, record, signal_after, event) {
- if (RecordSyncShareImpl(arg0, record, signal_after) && event)
- event->Signal();
+ACTION_P2(RecordSyncShareMultiple, record, quit_after) {
+ RecordSyncShareImpl(arg0, record);
+ EXPECT_LE(record->times.size(), quit_after);
+ if (record->times.size() >= quit_after) {
+ QuitLoopNow();
+ }
}
-ACTION_P(SignalEvent, event) {
- SyncerThreadTest::SignalWaitableEvent(event);
+ACTION(AddFailureAndQuitLoopNow) {
+ ADD_FAILURE();
+ QuitLoopNow();
+}
+
+ACTION(QuitLoopNowAction) {
+ QuitLoopNow();
}
// Test nudge scheduling.
-TEST_F(SyncerThreadTest, Nudge) {
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, Nudge) {
SyncShareRecords records;
syncable::ModelTypeBitSet model_types;
model_types[syncable::BOOKMARKS] = true;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))))
+ WithArg<0>(RecordSyncShare(&records))))
.RetiresOnSaturation();
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types,
- FROM_HERE);
- done.TimedWait(timeout());
- EXPECT_EQ(1U, records.snapshots.size());
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
+ RunLoop();
+
+ ASSERT_EQ(1U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types,
records.snapshots[0]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
records.snapshots[0]->source.updates_source);
+ Mock::VerifyAndClearExpectations(syncer());
+
// Make sure a second, later, nudge is unaffected by first (no coalescing).
SyncShareRecords records2;
model_types[syncable::BOOKMARKS] = false;
model_types[syncable::AUTOFILL] = true;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records2, 1U, &done))));
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types,
- FROM_HERE);
- done.TimedWait(timeout());
+ WithArg<0>(RecordSyncShare(&records2))));
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
+ RunLoop();
- EXPECT_EQ(1U, records2.snapshots.size());
+ ASSERT_EQ(1U, records2.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types,
records2.snapshots[0]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
@@ -234,23 +276,23 @@ TEST_F(SyncerThreadTest, Nudge) {
// Make sure a regular config command is scheduled fine in the absence of any
// errors.
-TEST_F(SyncerThreadTest, Config) {
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, Config) {
SyncShareRecords records;
syncable::ModelTypeBitSet model_types;
model_types[syncable::BOOKMARKS] = true;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&records))));
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
- syncer_thread()->ScheduleConfig(model_types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- done.TimedWait(timeout());
+ scheduler()->ScheduleConfig(
+ model_types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
- EXPECT_EQ(1U, records.snapshots.size());
+ ASSERT_EQ(1U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types,
records.snapshots[0]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
@@ -258,9 +300,7 @@ TEST_F(SyncerThreadTest, Config) {
}
// Simulate a failure and make sure the config request is retried.
-TEST_F(SyncerThreadTest, ConfigWithBackingOff) {
- base::WaitableEvent done(false, false);
- base::WaitableEvent* dummy = NULL;
+TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
@@ -270,17 +310,22 @@ TEST_F(SyncerThreadTest, ConfigWithBackingOff) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- WithArg<0>(RecordSyncShare(&records, 1U, dummy))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&records))));
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
- syncer_thread()->ScheduleConfig(model_types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- done.TimedWait(timeout());
+ ASSERT_EQ(0U, records.snapshots.size());
+ scheduler()->ScheduleConfig(
+ model_types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
- EXPECT_EQ(2U, records.snapshots.size());
+ ASSERT_EQ(1U, records.snapshots.size());
+ RunLoop();
+
+ ASSERT_EQ(2U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types,
records.snapshots[1]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION,
@@ -289,13 +334,10 @@ TEST_F(SyncerThreadTest, ConfigWithBackingOff) {
// Issue 2 config commands. Second one right after the first has failed
// and make sure LATEST is executed.
-TEST_F(SyncerThreadTest, MultipleConfigWithBackingOff) {
+TEST_F(SyncSchedulerTest, MultipleConfigWithBackingOff) {
syncable::ModelTypeBitSet model_types1, model_types2;
model_types1[syncable::BOOKMARKS] = true;
model_types2[syncable::AUTOFILL] = true;
- base::WaitableEvent done(false, false);
- base::WaitableEvent done1(false, false);
- base::WaitableEvent* dummy = NULL;
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(30)));
@@ -303,24 +345,29 @@ TEST_F(SyncerThreadTest, MultipleConfigWithBackingOff) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- WithArg<0>(RecordSyncShare(&records, 1U, dummy))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- WithArg<0>(RecordSyncShare(&records, 1U, &done1))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&records))));
+
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
+ ASSERT_EQ(0U, records.snapshots.size());
+ scheduler()->ScheduleConfig(
+ model_types1, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
- syncer_thread()->ScheduleConfig(model_types1,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ ASSERT_EQ(1U, records.snapshots.size());
+ scheduler()->ScheduleConfig(
+ model_types2, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
- // done1 indicates the first config failed.
- done1.TimedWait(timeout());
- syncer_thread()->ScheduleConfig(model_types2,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- done.TimedWait(timeout());
+ ASSERT_EQ(2U, records.snapshots.size());
+ RunLoop();
- EXPECT_EQ(3U, records.snapshots.size());
+ ASSERT_EQ(3U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types2,
records.snapshots[2]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
@@ -329,13 +376,9 @@ TEST_F(SyncerThreadTest, MultipleConfigWithBackingOff) {
// Issue a nudge when the config has failed. Make sure both the config and
// nudge are executed.
-TEST_F(SyncerThreadTest, NudgeWithConfigWithBackingOff) {
+TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
syncable::ModelTypeBitSet model_types;
model_types[syncable::BOOKMARKS] = true;
- base::WaitableEvent done(false, false);
- base::WaitableEvent done1(false, false);
- base::WaitableEvent done2(false, false);
- base::WaitableEvent* dummy = NULL;
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
@@ -343,27 +386,36 @@ TEST_F(SyncerThreadTest, NudgeWithConfigWithBackingOff) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- WithArg<0>(RecordSyncShare(&records, 1U, dummy))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- WithArg<0>(RecordSyncShare(&records, 1U, &done1))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done2))))
+ WithArg<0>(RecordSyncShare(&records))))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&records))));
+
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
+
+ ASSERT_EQ(0U, records.snapshots.size());
+ scheduler()->ScheduleConfig(
+ model_types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
+
+ ASSERT_EQ(1U, records.snapshots.size());
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
+ RunLoop();
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
+ ASSERT_EQ(2U, records.snapshots.size());
+ RunLoop();
- syncer_thread()->ScheduleConfig(model_types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- done1.TimedWait(timeout());
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types,
- FROM_HERE);
+ // Now change the mode so nudge can execute.
+ ASSERT_EQ(3U, records.snapshots.size());
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
- // done2 indicates config suceeded. Now change the mode so nudge can execute.
- done2.TimedWait(timeout());
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- EXPECT_EQ(4U, records.snapshots.size());
+ ASSERT_EQ(4U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types,
records.snapshots[2]->source.types));
@@ -377,43 +429,45 @@ TEST_F(SyncerThreadTest, NudgeWithConfigWithBackingOff) {
}
-
// Test that nudges are coalesced.
-TEST_F(SyncerThreadTest, NudgeCoalescing) {
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, NudgeCoalescing) {
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
SyncShareRecords r;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&r, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&r))));
syncable::ModelTypeBitSet types1, types2, types3;
types1[syncable::BOOKMARKS] = true;
types2[syncable::AUTOFILL] = true;
types3[syncable::THEMES] = true;
- TimeDelta delay = TimeDelta::FromMilliseconds(
- TestTimeouts::tiny_timeout_ms());
+ TimeDelta delay = zero();
TimeTicks optimal_time = TimeTicks::Now() + delay;
- syncer_thread()->ScheduleNudge(delay, NUDGE_SOURCE_UNKNOWN, types1,
- FROM_HERE);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types2,
- FROM_HERE);
- done.TimedWait(timeout());
+ scheduler()->ScheduleNudge(
+ delay, NUDGE_SOURCE_UNKNOWN, types1, FROM_HERE);
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, types2, FROM_HERE);
+ RunLoop();
- EXPECT_EQ(1U, r.snapshots.size());
+ ASSERT_EQ(1U, r.snapshots.size());
EXPECT_GE(r.times[0], optimal_time);
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(
types1 | types2, r.snapshots[0]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
r.snapshots[0]->source.updates_source);
+ Mock::VerifyAndClearExpectations(syncer());
+
SyncShareRecords r2;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&r2, 1U, &done))));
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_NOTIFICATION, types3,
- FROM_HERE);
- done.TimedWait(timeout());
- EXPECT_EQ(1U, r2.snapshots.size());
+ WithArg<0>(RecordSyncShare(&r2))));
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_NOTIFICATION, types3, FROM_HERE);
+ RunLoop();
+
+ ASSERT_EQ(1U, r2.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(types3,
r2.snapshots[0]->source.types));
EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION,
@@ -421,65 +475,68 @@ TEST_F(SyncerThreadTest, NudgeCoalescing) {
}
// Test nudge scheduling.
-TEST_F(SyncerThreadTest, NudgeWithPayloads) {
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, NudgeWithPayloads) {
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
SyncShareRecords records;
syncable::ModelTypePayloadMap model_types_with_payloads;
model_types_with_payloads[syncable::BOOKMARKS] = "test";
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, &done))))
+ WithArg<0>(RecordSyncShare(&records))))
.RetiresOnSaturation();
- syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL,
- model_types_with_payloads, FROM_HERE);
- done.TimedWait(timeout());
+ scheduler()->ScheduleNudgeWithPayloads(
+ zero(), NUDGE_SOURCE_LOCAL, model_types_with_payloads, FROM_HERE);
+ RunLoop();
- EXPECT_EQ(1U, records.snapshots.size());
+ ASSERT_EQ(1U, records.snapshots.size());
EXPECT_EQ(model_types_with_payloads, records.snapshots[0]->source.types);
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
records.snapshots[0]->source.updates_source);
+ Mock::VerifyAndClearExpectations(syncer());
+
// Make sure a second, later, nudge is unaffected by first (no coalescing).
SyncShareRecords records2;
model_types_with_payloads.erase(syncable::BOOKMARKS);
model_types_with_payloads[syncable::AUTOFILL] = "test2";
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records2, 1U, &done))));
- syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL,
- model_types_with_payloads, FROM_HERE);
- done.TimedWait(timeout());
+ WithArg<0>(RecordSyncShare(&records2))));
+ scheduler()->ScheduleNudgeWithPayloads(
+ zero(), NUDGE_SOURCE_LOCAL, model_types_with_payloads, FROM_HERE);
+ RunLoop();
- EXPECT_EQ(1U, records2.snapshots.size());
+ ASSERT_EQ(1U, records2.snapshots.size());
EXPECT_EQ(model_types_with_payloads, records2.snapshots[0]->source.types);
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
records2.snapshots[0]->source.updates_source);
}
// Test that nudges are coalesced.
-TEST_F(SyncerThreadTest, NudgeWithPayloadsCoalescing) {
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, NudgeWithPayloadsCoalescing) {
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
SyncShareRecords r;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&r, 1U, &done))));
+ WithArg<0>(RecordSyncShare(&r))));
syncable::ModelTypePayloadMap types1, types2, types3;
types1[syncable::BOOKMARKS] = "test1";
types2[syncable::AUTOFILL] = "test2";
types3[syncable::THEMES] = "test3";
- TimeDelta delay = TimeDelta::FromMilliseconds(
- TestTimeouts::tiny_timeout_ms());
+ TimeDelta delay = zero();
TimeTicks optimal_time = TimeTicks::Now() + delay;
- syncer_thread()->ScheduleNudgeWithPayloads(delay, NUDGE_SOURCE_UNKNOWN,
- types1, FROM_HERE);
- syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL,
- types2, FROM_HERE);
- done.TimedWait(timeout());
+ scheduler()->ScheduleNudgeWithPayloads(
+ delay, NUDGE_SOURCE_UNKNOWN, types1, FROM_HERE);
+ scheduler()->ScheduleNudgeWithPayloads(
+ zero(), NUDGE_SOURCE_LOCAL, types2, FROM_HERE);
+ RunLoop();
- EXPECT_EQ(1U, r.snapshots.size());
+ ASSERT_EQ(1U, r.snapshots.size());
EXPECT_GE(r.times[0], optimal_time);
syncable::ModelTypePayloadMap coalesced_types;
syncable::CoalescePayloads(&coalesced_types, types1);
@@ -488,121 +545,138 @@ TEST_F(SyncerThreadTest, NudgeWithPayloadsCoalescing) {
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
r.snapshots[0]->source.updates_source);
+ Mock::VerifyAndClearExpectations(syncer());
+
SyncShareRecords r2;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&r2, 1U, &done))));
- syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_NOTIFICATION,
- types3, FROM_HERE);
- done.TimedWait(timeout());
- EXPECT_EQ(1U, r2.snapshots.size());
+ WithArg<0>(RecordSyncShare(&r2))));
+ scheduler()->ScheduleNudgeWithPayloads(
+ zero(), NUDGE_SOURCE_NOTIFICATION, types3, FROM_HERE);
+ RunLoop();
+
+ ASSERT_EQ(1U, r2.snapshots.size());
EXPECT_EQ(types3, r2.snapshots[0]->source.types);
EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION,
r2.snapshots[0]->source.updates_source);
}
// Test that polling works as expected.
-TEST_F(SyncerThreadTest, Polling) {
+TEST_F(SyncSchedulerTest, Polling) {
SyncShareRecords records;
- base::WaitableEvent done(false, false);
TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll_interval);
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done))));
+ WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
+
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ // Run again to wait for polling.
+ RunLoop();
+ scheduler()->Stop();
AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval);
}
// Test that the short poll interval is used.
-TEST_F(SyncerThreadTest, PollNotificationsDisabled) {
+TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
SyncShareRecords records;
- base::WaitableEvent done(false, false);
TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
- syncer_thread()->OnReceivedShortPollIntervalUpdate(poll_interval);
- syncer_thread()->set_notifications_enabled(false);
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done))));
+ WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
+
+ scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
+ scheduler()->set_notifications_enabled(false);
TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ // Run again to wait for polling.
+ RunLoop();
+ scheduler()->Stop();
AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval);
}
// Test that polling intervals are updated when needed.
-TEST_F(SyncerThreadTest, PollIntervalUpdate) {
+TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
SyncShareRecords records;
- base::WaitableEvent done(false, false);
TimeDelta poll1(TimeDelta::FromMilliseconds(120));
TimeDelta poll2(TimeDelta::FromMilliseconds(30));
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll1);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
.WillOnce(WithArg<0>(
sessions::test_util::SimulatePollIntervalUpdate(poll2)))
- .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done))));
+ .WillRepeatedly(
+ DoAll(Invoke(sessions::test_util::SimulateSuccess),
+ WithArg<0>(
+ RecordSyncShareMultiple(&records, kMinNumSamples))));
TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ // Run again to wait for polling.
+ RunLoop();
+ scheduler()->Stop();
AnalyzePollRun(records, kMinNumSamples, optimal_start, poll2);
}
// Test that a sync session is run through to completion.
-TEST_F(SyncerThreadTest, HasMoreToSync) {
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, HasMoreToSync) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- SignalEvent(&done)));
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(),
- FROM_HERE);
- done.TimedWait(timeout());
+ QuitLoopNowAction()));
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), FROM_HERE);
+ RunLoop();
// If more nudges are scheduled, they'll be waited on by TearDown, and would
// cause our expectation to break.
}
// Test that no syncing occurs when throttled.
-TEST_F(SyncerThreadTest, ThrottlingDoesThrottle) {
+TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
syncable::ModelTypeBitSet types;
types[syncable::BOOKMARKS] = true;
- base::WaitableEvent done(false, false);
TimeDelta poll(TimeDelta::FromMilliseconds(5));
TimeDelta throttle(TimeDelta::FromMinutes(10));
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
- .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle)));
+ .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle)))
+ .WillRepeatedly(AddFailureAndQuitLoopNow());
+
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
+ PumpLoop();
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types,
- FROM_HERE);
- FlushLastTask(&done);
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
- syncer_thread()->ScheduleConfig(types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- FlushLastTask(&done);
+ scheduler()->ScheduleConfig(
+ types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ PumpLoop();
}
-TEST_F(SyncerThreadTest, ThrottlingExpires) {
+TEST_F(SyncSchedulerTest, ThrottlingExpires) {
SyncShareRecords records;
- base::WaitableEvent done(false, false);
TimeDelta poll(TimeDelta::FromMilliseconds(15));
TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
TimeDelta throttle2(TimeDelta::FromMinutes(10));
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
@@ -610,110 +684,116 @@ TEST_F(SyncerThreadTest, ThrottlingExpires) {
.RetiresOnSaturation();
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done))));
+ WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+ // Run again to wait for polling.
+ RunLoop();
+
+ scheduler()->Stop();
AnalyzePollRun(records, kMinNumSamples, optimal_start, poll);
}
// Test nudges / polls don't run in config mode and config tasks do.
-TEST_F(SyncerThreadTest, ConfigurationMode) {
+TEST_F(SyncSchedulerTest, ConfigurationMode) {
TimeDelta poll(TimeDelta::FromMilliseconds(15));
SyncShareRecords records;
- base::WaitableEvent done(false, false);
- base::WaitableEvent* dummy = NULL;
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce((Invoke(sessions::test_util::SimulateSuccess),
- WithArg<0>(RecordSyncShare(&records, 1U, dummy))));
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
+ WithArg<0>(RecordSyncShare(&records))));
+
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
+
syncable::ModelTypeBitSet nudge_types;
nudge_types[syncable::AUTOFILL] = true;
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types,
- FROM_HERE);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types,
- FROM_HERE);
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
syncable::ModelTypeBitSet config_types;
config_types[syncable::BOOKMARKS] = true;
- syncer_thread()->ScheduleConfig(config_types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- FlushLastTask(&done);
- syncer_thread()->Stop();
+ scheduler()->ScheduleConfig(
+ config_types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ RunLoop();
- EXPECT_EQ(1U, records.snapshots.size());
+ ASSERT_EQ(1U, records.snapshots.size());
EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(config_types,
records.snapshots[0]->source.types));
}
// Test that exponential backoff is properly triggered.
-TEST_F(SyncerThreadTest, BackoffTriggers) {
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, BackoffTriggers) {
UseMockDelayProvider();
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- SignalEvent(&done)));
- EXPECT_FALSE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_FALSE(GetBackoffAndResetTest());
// Note GetBackoffAndResetTest clears mocks and re-instantiates the syncer.
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- SignalEvent(&done)));
- EXPECT_FALSE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_FALSE(GetBackoffAndResetTest());
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
.WillRepeatedly(DoAll(Invoke(
sessions::test_util::SimulateDownloadUpdatesFailed),
- SignalEvent(&done)));
- EXPECT_TRUE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_TRUE(GetBackoffAndResetTest());
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- SignalEvent(&done)));
- EXPECT_TRUE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_TRUE(GetBackoffAndResetTest());
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
.WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- SignalEvent(&done)));
- EXPECT_FALSE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_FALSE(GetBackoffAndResetTest());
EXPECT_CALL(*syncer(), SyncShare(_,_,_))
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- SignalEvent(&done)));
- EXPECT_FALSE(GetBackoffAndResetTest(&done));
+ QuitLoopNowAction()));
+ EXPECT_FALSE(GetBackoffAndResetTest());
}
// Test that no polls or extraneous nudges occur when in backoff.
-TEST_F(SyncerThreadTest, BackoffDropsJobs) {
+TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
SyncShareRecords r;
TimeDelta poll(TimeDelta::FromMilliseconds(5));
- base::WaitableEvent done(false, false);
syncable::ModelTypeBitSet types;
types[syncable::BOOKMARKS] = true;
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
UseMockDelayProvider();
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(2)
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- RecordSyncShareAndPostSignal(&r, 2U, this, &done)));
- EXPECT_CALL(*delay(), GetDelay(_))
- .WillRepeatedly(Return(TimeDelta::FromDays(1)));
+ RecordSyncShareMultiple(&r, 2U)));
+ EXPECT_CALL(*delay(), GetDelay(_)).
+ WillRepeatedly(Return(TimeDelta::FromDays(1)));
+
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- ASSERT_TRUE(done.TimedWait(timeout()));
- done.Reset();
+ // Run again to wait for polling.
+ RunLoop();
+
+ // Pump loop to get rid of nudge.
+ PumpLoop();
Mock::VerifyAndClearExpectations(syncer());
- EXPECT_EQ(2U, r.snapshots.size());
+ ASSERT_EQ(2U, r.snapshots.size());
EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC,
r.snapshots[0]->source.updates_source);
EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION,
@@ -721,43 +801,45 @@ TEST_F(SyncerThreadTest, BackoffDropsJobs) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1)
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- RecordSyncShareAndPostSignal(&r, 1U, this, &done)));
+ RecordSyncShare(&r)));
// We schedule a nudge with enough delay (10X poll interval) that at least
// one or two polls would have taken place. The nudge should succeed.
- syncer_thread()->ScheduleNudge(poll * 10, NUDGE_SOURCE_LOCAL, types,
- FROM_HERE);
- ASSERT_TRUE(done.TimedWait(timeout()));
- done.Reset();
+ scheduler()->ScheduleNudge(
+ poll * 10, NUDGE_SOURCE_LOCAL, types, FROM_HERE);
+ RunLoop();
Mock::VerifyAndClearExpectations(syncer());
Mock::VerifyAndClearExpectations(delay());
- EXPECT_EQ(3U, r.snapshots.size());
+ ASSERT_EQ(3U, r.snapshots.size());
EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
r.snapshots[2]->source.updates_source);
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(0);
EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
- syncer_thread()->ScheduleConfig(types,
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- FlushLastTask(&done);
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleConfig(
+ types, sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ PumpLoop();
+
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types,
- FROM_HERE);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types,
- FROM_HERE);
- FlushLastTask(&done);
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
+ PumpLoop();
}
// Test that backoff is shaping traffic properly with consecutive errors.
-TEST_F(SyncerThreadTest, BackoffElevation) {
+TEST_F(SyncSchedulerTest, BackoffElevation) {
SyncShareRecords r;
const TimeDelta poll(TimeDelta::FromMilliseconds(10));
- base::WaitableEvent done(false, false);
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
UseMockDelayProvider();
const TimeDelta first = TimeDelta::FromSeconds(1);
@@ -768,7 +850,7 @@ TEST_F(SyncerThreadTest, BackoffElevation) {
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(kMinNumSamples)
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
- RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done)));
+ RecordSyncShareMultiple(&r, kMinNumSamples)));
EXPECT_CALL(*delay(), GetDelay(Eq(first))).WillOnce(Return(second))
.RetiresOnSaturation();
@@ -778,9 +860,13 @@ TEST_F(SyncerThreadTest, BackoffElevation) {
.RetiresOnSaturation();
EXPECT_CALL(*delay(), GetDelay(Eq(fourth))).WillOnce(Return(fifth));
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- ASSERT_TRUE(done.TimedWait(timeout()));
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+ // Run again to wait for polling.
+ RunLoop();
+
+ ASSERT_EQ(kMinNumSamples, r.snapshots.size());
EXPECT_GE(r.times[2] - r.times[1], second);
EXPECT_GE(r.times[3] - r.times[2], third);
EXPECT_GE(r.times[4] - r.times[3], fourth);
@@ -788,11 +874,10 @@ TEST_F(SyncerThreadTest, BackoffElevation) {
// Test that things go back to normal once a canary task makes forward progress
// following a succession of failures.
-TEST_F(SyncerThreadTest, BackoffRelief) {
+TEST_F(SyncSchedulerTest, BackoffRelief) {
SyncShareRecords r;
const TimeDelta poll(TimeDelta::FromMilliseconds(10));
- base::WaitableEvent done(false, false);
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
UseMockDelayProvider();
const TimeDelta backoff = TimeDelta::FromMilliseconds(100);
@@ -801,14 +886,18 @@ TEST_F(SyncerThreadTest, BackoffRelief) {
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
- RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done)));
+ RecordSyncShareMultiple(&r, kMinNumSamples)));
EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
// Optimal start for the post-backoff poll party.
TimeTicks optimal_start = TimeTicks::Now() + poll + backoff;
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ // Run again to wait for polling.
+ RunLoop();
+
+ scheduler()->Stop();
// Check for healthy polling after backoff is relieved.
// Can't use AnalyzePollRun because first sync is a continuation. Bleh.
@@ -822,96 +911,106 @@ TEST_F(SyncerThreadTest, BackoffRelief) {
}
}
-TEST_F(SyncerThreadTest, GetRecommendedDelay) {
+TEST_F(SyncSchedulerTest, GetRecommendedDelay) {
EXPECT_LE(TimeDelta::FromSeconds(0),
- SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(0)));
+ SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(0)));
EXPECT_LE(TimeDelta::FromSeconds(1),
- SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(1)));
+ SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(1)));
EXPECT_LE(TimeDelta::FromSeconds(50),
- SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(50)));
+ SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(50)));
EXPECT_LE(TimeDelta::FromSeconds(10),
- SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(10)));
+ SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(10)));
EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
- SyncerThread::GetRecommendedDelay(
+ SyncScheduler::GetRecommendedDelay(
TimeDelta::FromSeconds(kMaxBackoffSeconds)));
EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
- SyncerThread::GetRecommendedDelay(
+ SyncScheduler::GetRecommendedDelay(
TimeDelta::FromSeconds(kMaxBackoffSeconds + 1)));
}
// Test that appropriate syncer steps are requested for each job type.
-TEST_F(SyncerThreadTest, SyncerSteps) {
+TEST_F(SyncSchedulerTest, SyncerSteps) {
// Nudges.
- base::WaitableEvent done(false, false);
EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END))
.Times(1);
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(),
- FROM_HERE);
- FlushLastTask(&done);
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), FROM_HERE);
+ PumpLoop();
+ // Pump again to run job.
+ PumpLoop();
+
+ scheduler()->Stop();
Mock::VerifyAndClearExpectations(syncer());
// ClearUserData.
EXPECT_CALL(*syncer(), SyncShare(_, CLEAR_PRIVATE_DATA, SYNCER_END))
.Times(1);
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleClearUserData();
- FlushLastTask(&done);
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleClearUserData();
+ PumpLoop();
+ PumpLoop();
+
+ scheduler()->Stop();
+
Mock::VerifyAndClearExpectations(syncer());
// Configuration.
EXPECT_CALL(*syncer(), SyncShare(_, DOWNLOAD_UPDATES, APPLY_UPDATES));
- syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL);
- syncer_thread()->ScheduleConfig(ModelTypeBitSet(),
- sync_api::CONFIGURE_REASON_RECONFIGURATION);
- FlushLastTask(&done);
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleConfig(
+ ModelTypeBitSet(), sync_api::CONFIGURE_REASON_RECONFIGURATION);
+ PumpLoop();
+ PumpLoop();
+
+ scheduler()->Stop();
Mock::VerifyAndClearExpectations(syncer());
// Poll.
EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END))
.Times(AtLeast(1))
- .WillRepeatedly(SignalEvent(&done));
+ .WillRepeatedly(QuitLoopNowAction());
const TimeDelta poll(TimeDelta::FromMilliseconds(10));
- syncer_thread()->OnReceivedLongPollIntervalUpdate(poll);
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- done.TimedWait(timeout());
- syncer_thread()->Stop();
+ scheduler()->OnReceivedLongPollIntervalUpdate(poll);
+
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ // Run again to wait for polling.
+ RunLoop();
+
+ scheduler()->Stop();
Mock::VerifyAndClearExpectations(syncer());
- done.Reset();
}
// Test config tasks don't run during normal mode.
// TODO(tim): Implement this test and then the functionality!
-TEST_F(SyncerThreadTest, DISABLED_NoConfigDuringNormal) {
+TEST_F(SyncSchedulerTest, DISABLED_NoConfigDuringNormal) {
}
// Test that starting the syncer thread without a valid connection doesn't
// break things when a connection is detected.
-TEST_F(SyncerThreadTest, StartWhenNotConnected) {
- base::WaitableEvent done(false, false);
- MessageLoop cur;
+TEST_F(SyncSchedulerTest, StartWhenNotConnected) {
connection()->SetServerNotReachable();
- EXPECT_CALL(*syncer(), SyncShare(_,_,_)).WillOnce(SignalEvent(&done));
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(),
- FROM_HERE);
- FlushLastTask(&done);
+ EXPECT_CALL(*syncer(), SyncShare(_,_,_)).WillOnce(QuitLoopNowAction());
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
- connection()->SetServerReachable();
- cur.PostTask(FROM_HERE, NewRunnableFunction(
- &SyncerThreadTest::QuitMessageLoop));
- cur.Run();
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), FROM_HERE);
+ // Should save the nudge for until after the server is reachable.
+ PumpLoop();
- // By now, the server connection event should have been posted to the
- // SyncerThread.
- FlushLastTask(&done);
- done.TimedWait(timeout());
+ connection()->SetServerReachable();
+ PumpLoop();
}
-TEST_F(SyncerThreadTest, SetsPreviousRoutingInfo) {
- base::WaitableEvent done(false, false);
+TEST_F(SyncSchedulerTest, SetsPreviousRoutingInfo) {
ModelSafeRoutingInfo info;
EXPECT_TRUE(info == context()->previous_session_routing_info());
ModelSafeRoutingInfo expected;
@@ -919,16 +1018,18 @@ TEST_F(SyncerThreadTest, SetsPreviousRoutingInfo) {
ASSERT_FALSE(expected.empty());
EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1);
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
- syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(),
- FROM_HERE);
- FlushLastTask(&done);
- syncer_thread()->Stop();
+ StartSyncScheduler(SyncScheduler::NORMAL_MODE);
+ RunLoop();
+
+ scheduler()->ScheduleNudge(
+ zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), FROM_HERE);
+ PumpLoop();
+ // Pump again to run job.
+ PumpLoop();
+
+ scheduler()->Stop();
EXPECT_TRUE(expected == context()->previous_session_routing_info());
}
} // namespace browser_sync
-
-// SyncerThread won't outlive the test!
-DISABLE_RUNNABLE_METHOD_REFCOUNT(browser_sync::SyncerThreadTest);
diff --git a/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc b/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc
new file mode 100644
index 0000000..911c5db
--- /dev/null
+++ b/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop.h"
+#include "base/time.h"
+#include "chrome/browser/sync/engine/mock_model_safe_workers.h"
+#include "chrome/browser/sync/engine/sync_scheduler.h"
+#include "chrome/browser/sync/sessions/sync_session_context.h"
+#include "chrome/browser/sync/sessions/test_util.h"
+#include "chrome/test/sync/engine/mock_connection_manager.h"
+#include "chrome/test/sync/engine/test_directory_setter_upper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace browser_sync {
+using sessions::SyncSessionContext;
+using browser_sync::Syncer;
+
+class SyncSchedulerWhiteboxTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ syncdb_.SetUp();
+ Syncer* syncer = new Syncer();
+ registrar_.reset(MockModelSafeWorkerRegistrar::PassiveBookmarks());
+ connection_.reset(new MockConnectionManager(syncdb_.manager(), "Test"));
+ connection_->SetServerReachable();
+ context_ = new SyncSessionContext(connection_.get(), syncdb_.manager(),
+ registrar_.get(), std::vector<SyncEngineEventListener*>());
+ context_->set_notifications_enabled(true);
+ context_->set_account_name("Test");
+ scheduler_.reset(
+ new SyncScheduler("TestSyncSchedulerWhitebox", context_, syncer));
+ }
+
+ virtual void TearDown() {
+ scheduler_.reset();
+ syncdb_.TearDown();
+ }
+
+ void SetMode(SyncScheduler::Mode mode) {
+ scheduler_->mode_ = mode;
+ }
+
+ void SetLastSyncedTime(base::TimeTicks ticks) {
+ scheduler_->last_sync_session_end_time_ = ticks;
+ }
+
+ void SetServerConnection(bool connected) {
+ scheduler_->server_connection_ok_ = connected;
+ }
+
+ void ResetWaitInterval() {
+ scheduler_->wait_interval_.reset();
+ }
+
+ void SetWaitIntervalToThrottled() {
+ scheduler_->wait_interval_.reset(new SyncScheduler::WaitInterval(
+ SyncScheduler::WaitInterval::THROTTLED, TimeDelta::FromSeconds(1)));
+ }
+
+ void SetWaitIntervalToExponentialBackoff() {
+ scheduler_->wait_interval_.reset(
+ new SyncScheduler::WaitInterval(
+ SyncScheduler::WaitInterval::EXPONENTIAL_BACKOFF,
+ TimeDelta::FromSeconds(1)));
+ }
+
+ void SetWaitIntervalHadNudge(bool had_nudge) {
+ scheduler_->wait_interval_->had_nudge = had_nudge;
+ }
+
+ SyncScheduler::JobProcessDecision DecideOnJob(
+ const SyncScheduler::SyncSessionJob& job) {
+ return scheduler_->DecideOnJob(job);
+ }
+
+ void InitializeSyncerOnNormalMode() {
+ SetMode(SyncScheduler::NORMAL_MODE);
+ ResetWaitInterval();
+ SetServerConnection(true);
+ SetLastSyncedTime(base::TimeTicks::Now());
+ }
+
+ SyncScheduler::JobProcessDecision CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::SyncSessionJobPurpose purpose) {
+ struct SyncScheduler::SyncSessionJob job;
+ job.purpose = purpose;
+ job.scheduled_start = TimeTicks::Now();
+ return DecideOnJob(job);
+ }
+
+ private:
+ MessageLoop message_loop_;
+ scoped_ptr<SyncScheduler> scheduler_;
+ scoped_ptr<MockConnectionManager> connection_;
+ SyncSessionContext* context_;
+ scoped_ptr<MockModelSafeWorkerRegistrar> registrar_;
+ MockDirectorySetterUpper syncdb_;
+};
+
+TEST_F(SyncSchedulerWhiteboxTest, SaveNudge) {
+ InitializeSyncerOnNormalMode();
+
+ // Now set the mode to configure.
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+
+ SyncScheduler::JobProcessDecision decision =
+ CreateAndDecideJob(SyncScheduler::SyncSessionJob::NUDGE);
+
+ EXPECT_EQ(decision, SyncScheduler::SAVE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, ContinueNudge) {
+ InitializeSyncerOnNormalMode();
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::NUDGE);
+
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, DropPoll) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::POLL);
+
+ EXPECT_EQ(decision, SyncScheduler::DROP);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, ContinuePoll) {
+ InitializeSyncerOnNormalMode();
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::POLL);
+
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, ContinueConfiguration) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::CONFIGURATION);
+
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, SaveConfigurationWhileThrottled) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+
+ SetWaitIntervalToThrottled();
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::CONFIGURATION);
+
+ EXPECT_EQ(decision, SyncScheduler::SAVE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, SaveNudgeWhileThrottled) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+
+ SetWaitIntervalToThrottled();
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::NUDGE);
+
+ EXPECT_EQ(decision, SyncScheduler::SAVE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest,
+ ContinueClearUserDataUnderAllCircumstances) {
+ InitializeSyncerOnNormalMode();
+
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+ SetWaitIntervalToThrottled();
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::CLEAR_USER_DATA);
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+
+ SetMode(SyncScheduler::NORMAL_MODE);
+ SetWaitIntervalToExponentialBackoff();
+ decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::CLEAR_USER_DATA);
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, ContinueNudgeWhileExponentialBackOff) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::NORMAL_MODE);
+ SetWaitIntervalToExponentialBackoff();
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::NUDGE);
+
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, DropNudgeWhileExponentialBackOff) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::NORMAL_MODE);
+ SetWaitIntervalToExponentialBackoff();
+ SetWaitIntervalHadNudge(true);
+
+ SyncScheduler::JobProcessDecision decision = CreateAndDecideJob(
+ SyncScheduler::SyncSessionJob::NUDGE);
+
+ EXPECT_EQ(decision, SyncScheduler::DROP);
+}
+
+TEST_F(SyncSchedulerWhiteboxTest, ContinueCanaryJobConfig) {
+ InitializeSyncerOnNormalMode();
+ SetMode(SyncScheduler::CONFIGURATION_MODE);
+ SetWaitIntervalToExponentialBackoff();
+
+ struct SyncScheduler::SyncSessionJob job;
+ job.purpose = SyncScheduler::SyncSessionJob::CONFIGURATION;
+ job.scheduled_start = TimeTicks::Now();
+ job.is_canary_job = true;
+ SyncScheduler::JobProcessDecision decision = DecideOnJob(job);
+
+ EXPECT_EQ(decision, SyncScheduler::CONTINUE);
+}
+
+} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index 360b694..ef3f5b4 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -37,8 +37,8 @@
#include "chrome/browser/sync/engine/nudge_source.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
+#include "chrome/browser/sync/engine/sync_scheduler.h"
#include "chrome/browser/sync/engine/syncer.h"
-#include "chrome/browser/sync/engine/syncer_thread.h"
#include "chrome/browser/sync/engine/http_post_provider_factory.h"
#include "chrome/browser/sync/js_arg_list.h"
#include "chrome/browser/sync/js_backend.h"
@@ -86,7 +86,7 @@ using browser_sync::ServerConnectionEventListener;
using browser_sync::SyncEngineEvent;
using browser_sync::SyncEngineEventListener;
using browser_sync::Syncer;
-using browser_sync::SyncerThread;
+using browser_sync::SyncScheduler;
using browser_sync::kNigoriTag;
using browser_sync::sessions::SyncSessionContext;
using std::list;
@@ -106,7 +106,7 @@ typedef GoogleServiceAuthError AuthError;
static const int kThreadExitTimeoutMsec = 60000;
static const int kSSLPort = 443;
-static const int kSyncerThreadDelayMsec = 250;
+static const int kSyncSchedulerDelayMsec = 250;
#if defined(OS_CHROMEOS)
static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
@@ -1129,7 +1129,7 @@ class SyncManager::SyncInternal
public:
SyncInternal(const std::string& name, SyncManager* sync_manager)
: name_(name),
- core_message_loop_(NULL),
+ sync_loop_(NULL),
parent_router_(NULL),
sync_manager_(sync_manager),
registrar_(NULL),
@@ -1169,7 +1169,7 @@ class SyncManager::SyncInternal
}
virtual ~SyncInternal() {
- CHECK(!core_message_loop_);
+ CHECK(!sync_loop_);
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
@@ -1258,7 +1258,7 @@ class SyncManager::SyncInternal
SyncAPIServerConnectionManager* connection_manager() {
return connection_manager_.get();
}
- SyncerThread* syncer_thread() { return syncer_thread_.get(); }
+ SyncScheduler* scheduler() { return scheduler_.get(); }
UserShare* GetUserShare() { return &share_; }
// Return the currently active (validated) username for use with syncable
@@ -1275,6 +1275,8 @@ class SyncManager::SyncInternal
browser_sync::NudgeSource source, const ModelTypeBitSet& types,
const tracked_objects::Location& nudge_location);
+ void RequestEarlyExit();
+
// See SyncManager::Shutdown for information.
void Shutdown();
@@ -1539,7 +1541,7 @@ class SyncManager::SyncInternal
// constructing any transaction type.
UserShare share_;
- MessageLoop* core_message_loop_;
+ MessageLoop* sync_loop_;
// We have to lock around every observers_ access because it can get accessed
// from any thread and added to/removed from on the core thread.
@@ -1552,8 +1554,9 @@ class SyncManager::SyncInternal
// client (the Syncer) and the sync server.
scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
- // The thread that runs the Syncer. Needs to be explicitly Start()ed.
- scoped_ptr<SyncerThread> syncer_thread_;
+ // The scheduler that runs the Syncer. Needs to be explicitly
+ // Start()ed.
+ scoped_ptr<SyncScheduler> scheduler_;
// The SyncNotifier which notifies us when updates need to be downloaded.
sync_notifier::SyncNotifier* sync_notifier_;
@@ -1580,22 +1583,24 @@ class SyncManager::SyncInternal
// The instance is shared between the SyncManager and the Syncer.
ModelSafeWorkerRegistrar* registrar_;
- // Set to true once Init has been called, and we know of an authenticated
- // valid) username either from a fresh authentication attempt (as in
- // first-use case) or from a previous attempt stored in our UserSettings
- // (as in the steady-state), and the syncable::Directory has been opened,
- // meaning we are ready to accept changes. Protected by initialized_mutex_
- // as it can get read/set by both the SyncerThread and the AuthWatcherThread.
+ // Set to true once Init has been called, and we know of an
+ // authenticated valid) username either from a fresh authentication
+ // attempt (as in first-use case) or from a previous attempt stored
+ // in our UserSettings (as in the steady-state), and the
+ // syncable::Directory has been opened, meaning we are ready to
+ // accept changes. Protected by initialized_mutex_ as it can get
+ // read/set by both the SyncScheduler and the AuthWatcherThread.
bool initialized_;
mutable base::Lock initialized_mutex_;
- // True if the SyncManager should be running in test mode (no syncer thread
- // actually communicating with the server).
+ // True if the SyncManager should be running in test mode (no sync
+ // scheduler actually communicating with the server).
bool setup_for_test_mode_;
ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
- // Map used to store the notification info to be displayed in about:sync page.
+ // Map used to store the notification info to be displayed in
+ // about:sync page.
NotificationInfoMap notification_info_map_;
browser_sync::JsDirectoryChangeListener js_directory_change_listener_;
@@ -1694,30 +1699,31 @@ void SyncManager::RequestNudge(const tracked_objects::Location& location) {
}
void SyncManager::RequestClearServerData() {
- if (data_->syncer_thread())
- data_->syncer_thread()->ScheduleClearUserData();
+ if (data_->scheduler())
+ data_->scheduler()->ScheduleClearUserData();
}
void SyncManager::RequestConfig(const syncable::ModelTypeBitSet& types,
ConfigureReason reason) {
- if (!data_->syncer_thread()) {
- VLOG(0) << "SyncManager::RequestConfig: bailing out because syncer thread "
- << "null";
+ if (!data_->scheduler()) {
+ LOG(INFO)
+ << "SyncManager::RequestConfig: bailing out because scheduler is "
+ << "null";
return;
}
StartConfigurationMode(NULL);
- data_->syncer_thread()->ScheduleConfig(types, reason);
+ data_->scheduler()->ScheduleConfig(types, reason);
}
void SyncManager::StartConfigurationMode(ModeChangeCallback* callback) {
- if (!data_->syncer_thread()) {
- VLOG(0) << "SyncManager::StartConfigurationMode: could not start "
- << "configuration mode because because syncer thread is not "
- << "created";
+ if (!data_->scheduler()) {
+ LOG(INFO)
+ << "SyncManager::StartConfigurationMode: could not start "
+ << "configuration mode because because scheduler is null";
return;
}
- data_->syncer_thread()->Start(
- browser_sync::SyncerThread::CONFIGURATION_MODE, callback);
+ data_->scheduler()->Start(
+ browser_sync::SyncScheduler::CONFIGURATION_MODE, callback);
}
const std::string& SyncManager::GetAuthenticatedUsername() {
@@ -1740,8 +1746,8 @@ bool SyncManager::SyncInternal::Init(
VLOG(1) << "Starting SyncInternal initialization.";
- core_message_loop_ = MessageLoop::current();
- DCHECK(core_message_loop_);
+ sync_loop_ = MessageLoop::current();
+ DCHECK(sync_loop_);
registrar_ = model_safe_worker_registrar;
setup_for_test_mode_ = setup_for_test_mode;
@@ -1759,7 +1765,7 @@ bool SyncManager::SyncInternal::Init(
// TODO(akalin): CheckServerReachable() can block, which may cause jank if we
// try to shut down sync. Fix this.
- core_message_loop_->PostTask(FROM_HERE,
+ sync_loop_->PostTask(FROM_HERE,
method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
// Test mode does not use a syncer context or syncer thread.
@@ -1775,16 +1781,15 @@ bool SyncManager::SyncInternal::Init(
model_safe_worker_registrar,
listeners);
context->set_account_name(credentials.email);
- // The SyncerThread takes ownership of |context|.
- syncer_thread_.reset(
- new SyncerThread(name_, context, new Syncer()));
+ // The SyncScheduler takes ownership of |context|.
+ scheduler_.reset(new SyncScheduler(name_, context, new Syncer()));
}
bool signed_in = SignIn(credentials);
- if (signed_in && syncer_thread()) {
- syncer_thread()->Start(
- browser_sync::SyncerThread::CONFIGURATION_MODE, NULL);
+ if (signed_in && scheduler()) {
+ scheduler()->Start(
+ browser_sync::SyncScheduler::CONFIGURATION_MODE, NULL);
}
// Do this once the directory is opened.
@@ -1797,7 +1802,7 @@ void SyncManager::SyncInternal::BootstrapEncryption(
const std::string& restored_key_for_bootstrapping) {
syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
if (!lookup.good()) {
- VLOG(0) << "BootstrapEncryption: lookup not good so bailing out";
+ LOG(INFO) << "BootstrapEncryption: lookup not good so bailing out";
NOTREACHED();
return;
}
@@ -1842,12 +1847,11 @@ void SyncManager::SyncInternal::BootstrapEncryption(
}
void SyncManager::SyncInternal::StartSyncingNormally() {
- // Start the syncer thread. This won't actually
- // result in any syncing until at least the
- // DirectoryManager broadcasts the OPENED event,
- // and a valid server connection is detected.
- if (syncer_thread()) // NULL during certain unittests.
- syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
+ // Start the sync scheduler. This won't actually result in any
+ // syncing until at least the DirectoryManager broadcasts the OPENED
+ // event, and a valid server connection is detected.
+ if (scheduler()) // NULL during certain unittests.
+ scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL);
}
void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
@@ -1871,7 +1875,7 @@ void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
}
void SyncManager::SyncInternal::SendNotification() {
- DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
if (!sync_notifier_) {
VLOG(1) << "Not sending notification: sync_notifier_ is NULL";
return;
@@ -1916,7 +1920,7 @@ bool SyncManager::SyncInternal::OpenDirectory() {
}
bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
- DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK(share_.name.empty());
share_.name = credentials.email;
@@ -1947,7 +1951,7 @@ bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
void SyncManager::SyncInternal::UpdateCredentials(
const SyncCredentials& credentials) {
- DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
DCHECK_EQ(credentials.email, share_.name);
DCHECK(!credentials.email.empty());
DCHECK(!credentials.sync_token.empty());
@@ -1960,7 +1964,7 @@ void SyncManager::SyncInternal::UpdateCredentials(
}
void SyncManager::SyncInternal::UpdateEnabledTypes() {
- DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK_EQ(MessageLoop::current(), sync_loop_);
ModelSafeRoutingInfo routes;
registrar_->GetModelSafeRoutingInfo(&routes);
syncable::ModelTypeSet enabled_types;
@@ -2202,6 +2206,16 @@ browser_sync::JsBackend* SyncManager::GetJsBackend() {
return data_;
}
+void SyncManager::RequestEarlyExit() {
+ data_->RequestEarlyExit();
+}
+
+void SyncManager::SyncInternal::RequestEarlyExit() {
+ if (scheduler()) {
+ scheduler()->RequestEarlyExit();
+ }
+}
+
void SyncManager::Shutdown() {
data_->Shutdown();
}
@@ -2209,10 +2223,8 @@ void SyncManager::Shutdown() {
void SyncManager::SyncInternal::Shutdown() {
method_factory_.RevokeAll();
- if (syncer_thread()) {
- syncer_thread()->Stop();
- syncer_thread_.reset();
- }
+ // Automatically stops the scheduler.
+ scheduler_.reset();
// We NULL out sync_notifer_ so that any pending tasks do not
// trigger further notifications.
@@ -2221,18 +2233,17 @@ void SyncManager::SyncInternal::Shutdown() {
sync_notifier_->RemoveObserver(this);
}
- // |this| is about to be destroyed, so we have to ensure any messages
- // that were posted to core_thread_ before or during syncer thread shutdown
- // are flushed out, else they refer to garbage memory. SendNotification
- // is an example.
- // TODO(tim): Remove this monstrosity, perhaps with ObserverListTS once core
- // thread is removed. Bug 78190.
+ // |this| is about to be destroyed, so we have to ensure any
+ // messages that were posted to sync_thread_ are flushed out, else
+ // they refer to garbage memory. SendNotification is an example.
+ // TODO(akalin): Remove this monstrosity, perhaps with
+ // ObserverListTS once core thread is removed. Bug 78190.
{
- CHECK(core_message_loop_);
- bool old_state = core_message_loop_->NestableTasksAllowed();
- core_message_loop_->SetNestableTasksAllowed(true);
- core_message_loop_->RunAllPending();
- core_message_loop_->SetNestableTasksAllowed(old_state);
+ CHECK(sync_loop_);
+ bool old_state = sync_loop_->NestableTasksAllowed();
+ sync_loop_->SetNestableTasksAllowed(true);
+ sync_loop_->RunAllPending();
+ sync_loop_->SetNestableTasksAllowed(old_state);
}
net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
@@ -2248,7 +2259,7 @@ void SyncManager::SyncInternal::Shutdown() {
// handles to backing files.
share_.dir_manager.reset();
- core_message_loop_ = NULL;
+ sync_loop_ = NULL;
}
void SyncManager::SyncInternal::OnIPAddressChanged() {
@@ -2379,10 +2390,10 @@ void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
only_preference_changes = false;
}
}
- if (exists_unsynced_items && syncer_thread()) {
+ if (exists_unsynced_items && scheduler()) {
int nudge_delay = only_preference_changes ?
kPreferencesNudgeDelayMilliseconds : kDefaultNudgeDelayMilliseconds;
- core_message_loop_->PostTask(FROM_HERE,
+ sync_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &SyncInternal::RequestNudgeWithDataTypes,
TimeDelta::FromMilliseconds(nudge_delay),
browser_sync::NUDGE_SOURCE_LOCAL,
@@ -2466,8 +2477,8 @@ SyncManager::Status SyncManager::SyncInternal::GetStatus() {
void SyncManager::SyncInternal::RequestNudge(
const tracked_objects::Location& location) {
- if (syncer_thread())
- syncer_thread()->ScheduleNudge(
+ if (scheduler())
+ scheduler()->ScheduleNudge(
TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
ModelTypeBitSet(), location);
}
@@ -2476,14 +2487,15 @@ void SyncManager::SyncInternal::RequestNudgeWithDataTypes(
const TimeDelta& delay,
browser_sync::NudgeSource source, const ModelTypeBitSet& types,
const tracked_objects::Location& nudge_location) {
- if (syncer_thread())
- syncer_thread()->ScheduleNudge(delay, source, types, nudge_location);
+ if (scheduler())
+ scheduler()->ScheduleNudge(delay, source, types, nudge_location);
}
void SyncManager::SyncInternal::OnSyncEngineEvent(
const SyncEngineEvent& event) {
if (!HaveObservers()) {
- VLOG(0) << "OnSyncEngineEvent returning because observers_.size() is zero";
+ LOG(INFO)
+ << "OnSyncEngineEvent returning because observers_.size() is zero";
return;
}
@@ -2550,8 +2562,8 @@ void SyncManager::SyncInternal::OnSyncEngineEvent(
}
if (!initialized()) {
- VLOG(0) << "OnSyncCycleCompleted not sent because sync api is not "
- << "initialized";
+ LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
+ << "initialized";
return;
}
@@ -2572,7 +2584,7 @@ void SyncManager::SyncInternal::OnSyncEngineEvent(
(event.snapshot->syncer_status.num_successful_commits > 0);
if (is_notifiable_commit) {
allstatus_.IncrementNotifiableCommits();
- core_message_loop_->PostTask(
+ sync_loop_->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
@@ -2842,8 +2854,8 @@ void SyncManager::SyncInternal::OnNotificationStateChange(
VLOG(1) << "P2P: Notifications enabled = "
<< (notifications_enabled ? "true" : "false");
allstatus_.SetNotificationsEnabled(notifications_enabled);
- if (syncer_thread()) {
- syncer_thread()->set_notifications_enabled(notifications_enabled);
+ if (scheduler()) {
+ scheduler()->set_notifications_enabled(notifications_enabled);
}
if (parent_router_) {
DictionaryValue details;
@@ -2866,9 +2878,9 @@ void SyncManager::SyncInternal::UpdateNotificationInfo(
void SyncManager::SyncInternal::OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads) {
if (!type_payloads.empty()) {
- if (syncer_thread()) {
- syncer_thread()->ScheduleNudgeWithPayloads(
- TimeDelta::FromMilliseconds(kSyncerThreadDelayMsec),
+ if (scheduler()) {
+ scheduler()->ScheduleNudgeWithPayloads(
+ TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
browser_sync::NUDGE_SOURCE_NOTIFICATION,
type_payloads, FROM_HERE);
}
diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h
index 2db4020..ce18184 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -912,15 +912,14 @@ class SyncManager {
// types, as we do not currently support decrypting datatypes.
void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
- // Puts the SyncerThread into a mode where no normal nudge or poll traffic
+ // Puts the SyncScheduler into a mode where no normal nudge or poll traffic
// will occur, but calls to RequestConfig will be supported. If |callback|
- // is provided, it will be invoked (from the internal SyncerThread) when
+ // is provided, it will be invoked (from the internal SyncScheduler) when
// the thread has changed to configuration mode.
void StartConfigurationMode(ModeChangeCallback* callback);
- // For the new SyncerThread impl, this switches the mode of operation to
- // CONFIGURATION_MODE and schedules a config task to fetch updates for
- // |types|.
+ // Switches the mode of operation to CONFIGURATION_MODE and
+ // schedules a config task to fetch updates for |types|.
void RequestConfig(const syncable::ModelTypeBitSet& types,
sync_api::ConfigureReason reason);
@@ -1027,6 +1026,8 @@ class SyncManager {
// to the syncapi model.
void SaveChanges();
+ void RequestEarlyExit();
+
// Issue a final SaveChanges, close sqlite handles, and stop running threads.
// Must be called from the same thread that called Init().
void Shutdown();
diff --git a/chrome/browser/sync/engine/syncer_thread_whitebox_unittest.cc b/chrome/browser/sync/engine/syncer_thread_whitebox_unittest.cc
deleted file mode 100644
index 681474a..0000000
--- a/chrome/browser/sync/engine/syncer_thread_whitebox_unittest.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/time.h"
-#include "chrome/browser/sync/engine/mock_model_safe_workers.h"
-#include "chrome/browser/sync/engine/syncer_thread.h"
-#include "chrome/browser/sync/sessions/sync_session_context.h"
-#include "chrome/browser/sync/sessions/test_util.h"
-#include "chrome/test/sync/engine/mock_connection_manager.h"
-#include "chrome/test/sync/engine/test_directory_setter_upper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using base::TimeDelta;
-using base::TimeTicks;
-
-namespace browser_sync {
-using sessions::SyncSessionContext;
-using browser_sync::Syncer;
-
-class SyncerThreadWhiteboxTest : public testing::Test {
- public:
- virtual void SetUp() {
- syncdb_.SetUp();
- Syncer* syncer = new Syncer();
- registrar_.reset(MockModelSafeWorkerRegistrar::PassiveBookmarks());
- context_ = new SyncSessionContext(connection_.get(), syncdb_.manager(),
- registrar_.get(), std::vector<SyncEngineEventListener*>());
- context_->set_notifications_enabled(true);
- context_->set_account_name("Test");
- syncer_thread_.reset(
- new SyncerThread("TestSyncerThreadWhitebox", context_, syncer));
- }
-
- virtual void TearDown() {
- syncdb_.TearDown();
- }
-
- void SetMode(SyncerThread::Mode mode) {
- syncer_thread_->mode_ = mode;
- }
-
- void SetLastSyncedTime(base::TimeTicks ticks) {
- syncer_thread_->last_sync_session_end_time_ = ticks;
- }
-
- void SetServerConnection(bool connected) {
- syncer_thread_->server_connection_ok_ = connected;
- }
-
- void ResetWaitInterval() {
- syncer_thread_->wait_interval_.reset();
- }
-
- void SetWaitIntervalToThrottled() {
- syncer_thread_->wait_interval_.reset(new SyncerThread::WaitInterval(
- SyncerThread::WaitInterval::THROTTLED, TimeDelta::FromSeconds(1)));
- }
-
- void SetWaitIntervalToExponentialBackoff() {
- syncer_thread_->wait_interval_.reset(
- new SyncerThread::WaitInterval(
- SyncerThread::WaitInterval::EXPONENTIAL_BACKOFF,
- TimeDelta::FromSeconds(1)));
- }
-
- SyncerThread::JobProcessDecision DecideOnJob(
- const SyncerThread::SyncSessionJob& job) {
- return syncer_thread_->DecideOnJob(job);
- }
-
- void InitializeSyncerOnNormalMode() {
- SetMode(SyncerThread::NORMAL_MODE);
- ResetWaitInterval();
- SetServerConnection(true);
- SetLastSyncedTime(base::TimeTicks::Now());
- }
-
- SyncerThread::JobProcessDecision CreateAndDecideJob(
- SyncerThread::SyncSessionJob::SyncSessionJobPurpose purpose) {
- struct SyncerThread::SyncSessionJob job;
- job.purpose = purpose;
- job.scheduled_start = TimeTicks::Now();
- return DecideOnJob(job);
- }
-
- protected:
- scoped_ptr<SyncerThread> syncer_thread_;
-
- private:
- scoped_ptr<MockConnectionManager> connection_;
- SyncSessionContext* context_;
- //MockDelayProvider* delay_;
- scoped_ptr<MockModelSafeWorkerRegistrar> registrar_;
- MockDirectorySetterUpper syncdb_;
-};
-
-TEST_F(SyncerThreadWhiteboxTest, SaveNudge) {
- InitializeSyncerOnNormalMode();
-
- // Now set the mode to configure.
- SetMode(SyncerThread::CONFIGURATION_MODE);
-
- SyncerThread::JobProcessDecision decision =
- CreateAndDecideJob(SyncerThread::SyncSessionJob::NUDGE);
-
- EXPECT_EQ(decision, SyncerThread::SAVE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinueNudge) {
- InitializeSyncerOnNormalMode();
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::NUDGE);
-
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, DropPoll) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::CONFIGURATION_MODE);
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::POLL);
-
- EXPECT_EQ(decision, SyncerThread::DROP);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinuePoll) {
- InitializeSyncerOnNormalMode();
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::POLL);
-
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinueConfiguration) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::CONFIGURATION_MODE);
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::CONFIGURATION);
-
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, SaveConfigurationWhileThrottled) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::CONFIGURATION_MODE);
-
- SetWaitIntervalToThrottled();
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::CONFIGURATION);
-
- EXPECT_EQ(decision, SyncerThread::SAVE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, SaveNudgeWhileThrottled) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::CONFIGURATION_MODE);
-
- SetWaitIntervalToThrottled();
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::NUDGE);
-
- EXPECT_EQ(decision, SyncerThread::SAVE);
-
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinueClearUserDataUnderAllCircumstances) {
- InitializeSyncerOnNormalMode();
-
- SetMode(SyncerThread::CONFIGURATION_MODE);
- SetWaitIntervalToThrottled();
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::CLEAR_USER_DATA);
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-
- SetMode(SyncerThread::NORMAL_MODE);
- SetWaitIntervalToExponentialBackoff();
- decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::CLEAR_USER_DATA);
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinueNudgeWhileExponentialBackOff) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::NORMAL_MODE);
- SetWaitIntervalToExponentialBackoff();
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::NUDGE);
-
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, DropNudgeWhileExponentialBackOff) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::NORMAL_MODE);
- SetWaitIntervalToExponentialBackoff();
-
- syncer_thread_->wait_interval_->had_nudge = true;
-
- SyncerThread::JobProcessDecision decision = CreateAndDecideJob(
- SyncerThread::SyncSessionJob::NUDGE);
-
- EXPECT_EQ(decision, SyncerThread::DROP);
-}
-
-TEST_F(SyncerThreadWhiteboxTest, ContinueCanaryJobConfig) {
- InitializeSyncerOnNormalMode();
- SetMode(SyncerThread::CONFIGURATION_MODE);
- SetWaitIntervalToExponentialBackoff();
-
- struct SyncerThread::SyncSessionJob job;
- job.purpose = SyncerThread::SyncSessionJob::CONFIGURATION;
- job.scheduled_start = TimeTicks::Now();
- job.is_canary_job = true;
- SyncerThread::JobProcessDecision decision = DecideOnJob(job);
-
- EXPECT_EQ(decision, SyncerThread::CONTINUE);
-}
-
-} // namespace browser_sync
-
-// SyncerThread won't outlive the test!
-DISABLE_RUNNABLE_METHOD_REFCOUNT(
- browser_sync::SyncerThreadWhiteboxTest);
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 931721b..9316961 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -61,7 +61,7 @@ using sync_api::SyncCredentials;
SyncBackendHost::SyncBackendHost(Profile* profile)
: core_(new Core(profile->GetDebugName(),
ALLOW_THIS_IN_INITIALIZER_LIST(this))),
- core_thread_("Chrome_SyncCoreThread"),
+ sync_thread_("Chrome_SyncThread"),
frontend_loop_(MessageLoop::current()),
profile_(profile),
frontend_(NULL),
@@ -72,7 +72,7 @@ SyncBackendHost::SyncBackendHost(Profile* profile)
}
SyncBackendHost::SyncBackendHost()
- : core_thread_("Chrome_SyncCoreThread"),
+ : sync_thread_("Chrome_SyncThread"),
frontend_loop_(MessageLoop::current()),
profile_(NULL),
frontend_(NULL),
@@ -92,7 +92,7 @@ void SyncBackendHost::Initialize(
net::URLRequestContextGetter* baseline_context_getter,
const SyncCredentials& credentials,
bool delete_sync_data_folder) {
- if (!core_thread_.Start())
+ if (!sync_thread_.Start())
return;
frontend_ = frontend;
@@ -191,13 +191,13 @@ sync_api::HttpPostProviderFactory* SyncBackendHost::MakeHttpBridgeFactory(
}
void SyncBackendHost::InitCore(const Core::DoInitializeOptions& options) {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
options));
}
void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoUpdateCredentials,
credentials));
@@ -205,7 +205,7 @@ void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) {
void SyncBackendHost::StartSyncingWithServer() {
VLOG(1) << "SyncBackendHost::StartSyncingWithServer called.";
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoStartSyncing));
}
@@ -226,24 +226,25 @@ void SyncBackendHost::SetPassphrase(const std::string& passphrase,
core_->set_processing_passphrase();
// If encryption is enabled and we've got a SetPassphrase
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoSetPassphrase,
passphrase, is_explicit));
}
void SyncBackendHost::Shutdown(bool sync_disabled) {
// Thread shutdown should occur in the following order:
- // - SyncerThread
- // - CoreThread
+ // - Sync Thread
// - UI Thread (stops some time after we return from this call).
- if (core_thread_.IsRunning()) { // Not running in tests.
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ if (sync_thread_.IsRunning()) { // Not running in tests.
+ // TODO(akalin): Remove the need for this.
+ core_->syncapi()->RequestEarlyExit();
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoShutdown,
sync_disabled));
}
- // Before joining the core_thread_, we wait for the UIModelWorker to
+ // Before joining the sync_thread_, we wait for the UIModelWorker to
// give us the green light that it is not depending on the frontend_loop_ to
// process any more tasks. Stop() blocks until this termination condition
// is true.
@@ -251,7 +252,7 @@ void SyncBackendHost::Shutdown(bool sync_disabled) {
ui_worker()->Stop();
// Stop will return once the thread exits, which will be after DoShutdown
- // runs. DoShutdown needs to run from core_thread_ because the sync backend
+ // runs. DoShutdown needs to run from sync_thread_ because the sync backend
// requires any thread that opened sqlite handles to relinquish them
// personally. We need to join threads, because otherwise the main Chrome
// thread (ui loop) can exit before DoShutdown finishes, at which point
@@ -263,7 +264,7 @@ void SyncBackendHost::Shutdown(bool sync_disabled) {
// this, see bug 19757.
{
base::ThreadRestrictions::ScopedAllowIO allow_io;
- core_thread_.Stop();
+ sync_thread_.Stop();
}
registrar_.routing_info.clear();
@@ -427,8 +428,8 @@ void SyncBackendHost::StartConfiguration(Callback0::Type* callback) {
// Put syncer in the config mode. DTM will put us in normal mode once it is.
// done. This is to ensure we dont do a normal sync when we are doing model
// association.
- core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- core_.get(),&SyncBackendHost::Core::DoStartConfiguration, callback));
+ sync_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ core_.get(), &SyncBackendHost::Core::DoStartConfiguration, callback));
}
void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop() {
@@ -447,7 +448,7 @@ void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop() {
VLOG(1) << "Syncer in config mode. SBH executing"
<< "FinishConfigureDataTypesOnFrontendLoop";
if (pending_config_mode_state_->deleted_type) {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DeferNudgeForCleanup));
}
@@ -480,7 +481,7 @@ void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop() {
types_copy.set(syncable::NIGORI);
VLOG(1) << "SyncBackendHost(" << this << "):New Types added. "
<< "Calling DoRequestConfig";
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoRequestConfig,
types_copy,
@@ -490,14 +491,14 @@ void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop() {
pending_config_mode_state_.reset();
// Notify the SyncManager about the new types.
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoUpdateEnabledTypes));
}
void SyncBackendHost::EncryptDataTypes(
const syncable::ModelTypeSet& encrypted_types) {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoEncryptDataTypes,
encrypted_types));
@@ -509,7 +510,7 @@ syncable::ModelTypeSet SyncBackendHost::GetEncryptedDataTypes() const {
}
void SyncBackendHost::RequestNudge(const tracked_objects::Location& location) {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoRequestNudge,
location));
}
@@ -551,7 +552,7 @@ void SyncBackendHost::DeactivateDataType(
}
bool SyncBackendHost::RequestClearServerData() {
- core_thread_.message_loop()->PostTask(FROM_HERE,
+ sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoRequestClearServerData));
return true;
@@ -740,7 +741,7 @@ std::string MakeUserAgentForSyncapi() {
}
void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
processing_passphrase_ = false;
// Blow away the partial or corrupt sync data folder before doing any more
@@ -773,17 +774,17 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
void SyncBackendHost::Core::DoUpdateCredentials(
const SyncCredentials& credentials) {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
syncapi_->UpdateCredentials(credentials);
}
void SyncBackendHost::Core::DoUpdateEnabledTypes() {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
syncapi_->UpdateEnabledTypes();
}
void SyncBackendHost::Core::DoStartSyncing() {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
syncapi_->StartSyncingNormally();
if (deferred_nudge_for_cleanup_requested_)
syncapi_->RequestNudge(FROM_HERE);
@@ -792,7 +793,7 @@ void SyncBackendHost::Core::DoStartSyncing() {
void SyncBackendHost::Core::DoSetPassphrase(const std::string& passphrase,
bool is_explicit) {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
syncapi_->SetPassphrase(passphrase, is_explicit);
}
@@ -808,7 +809,7 @@ void SyncBackendHost::Core::set_processing_passphrase() {
void SyncBackendHost::Core::DoEncryptDataTypes(
const syncable::ModelTypeSet& encrypted_types) {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
syncapi_->EncryptDataTypes(encrypted_types);
}
@@ -832,7 +833,7 @@ UIModelWorker* SyncBackendHost::ui_worker() {
}
void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
- DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
+ DCHECK(MessageLoop::current() == host_->sync_thread_.message_loop());
save_changes_timer_.Stop();
syncapi_->Shutdown(); // Stops the SyncerThread.
@@ -964,7 +965,7 @@ void SyncBackendHost::Core::OnInitializationComplete() {
&Core::HandleInitalizationCompletedOnFrontendLoop));
// Initialization is complete, so we can schedule recurring SaveChanges.
- host_->core_thread_.message_loop()->PostTask(FROM_HERE,
+ host_->sync_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(this, &Core::StartSavingChanges));
}
@@ -1141,7 +1142,7 @@ void SyncBackendHost::Core::SetParentJsEventRouter(JsEventRouter* router) {
DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
DCHECK(router);
parent_router_ = router;
- MessageLoop* core_message_loop = host_->core_thread_.message_loop();
+ MessageLoop* core_message_loop = host_->sync_thread_.message_loop();
CHECK(core_message_loop);
core_message_loop->PostTask(
FROM_HERE,
@@ -1152,7 +1153,7 @@ void SyncBackendHost::Core::SetParentJsEventRouter(JsEventRouter* router) {
void SyncBackendHost::Core::RemoveParentJsEventRouter() {
DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
parent_router_ = NULL;
- MessageLoop* core_message_loop = host_->core_thread_.message_loop();
+ MessageLoop* core_message_loop = host_->sync_thread_.message_loop();
CHECK(core_message_loop);
core_message_loop->PostTask(
FROM_HERE,
@@ -1169,7 +1170,7 @@ void SyncBackendHost::Core::ProcessMessage(
const std::string& name, const JsArgList& args,
const JsEventHandler* sender) {
DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_);
- MessageLoop* core_message_loop = host_->core_thread_.message_loop();
+ MessageLoop* core_message_loop = host_->sync_thread_.message_loop();
CHECK(core_message_loop);
core_message_loop->PostTask(
FROM_HERE,
@@ -1179,7 +1180,7 @@ void SyncBackendHost::Core::ProcessMessage(
}
void SyncBackendHost::Core::ConnectChildJsEventRouter() {
- DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), host_->sync_thread_.message_loop());
// We need this check since AddObserver() can be called at most once
// for a given observer.
if (!syncapi_->GetJsBackend()->GetParentJsEventRouter()) {
@@ -1189,7 +1190,7 @@ void SyncBackendHost::Core::ConnectChildJsEventRouter() {
}
void SyncBackendHost::Core::DisconnectChildJsEventRouter() {
- DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), host_->sync_thread_.message_loop());
syncapi_->GetJsBackend()->RemoveParentJsEventRouter();
syncapi_->RemoveObserver(&sync_manager_observer_);
}
@@ -1197,12 +1198,12 @@ void SyncBackendHost::Core::DisconnectChildJsEventRouter() {
void SyncBackendHost::Core::DoProcessMessage(
const std::string& name, const JsArgList& args,
const JsEventHandler* sender) {
- DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), host_->sync_thread_.message_loop());
syncapi_->GetJsBackend()->ProcessMessage(name, args, sender);
}
void SyncBackendHost::Core::DeferNudgeForCleanup() {
- DCHECK_EQ(MessageLoop::current(), host_->core_thread_.message_loop());
+ DCHECK_EQ(MessageLoop::current(), host_->sync_thread_.message_loop());
deferred_nudge_for_cleanup_requested_ = true;
}
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 84b0537..d9c0ae5 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -178,7 +178,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Encrypts the specified datatypes and marks them as needing encryption on
// other machines. This affects all machines synced to this account and all
// data belonging to the specified types.
- // Note: actual work is done on core_thread_'s message loop.
+ // Note: actual work is done on sync_thread_'s message loop.
virtual void EncryptDataTypes(
const syncable::ModelTypeSet& encrypted_types);
@@ -338,22 +338,22 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// It calls us on a dedicated thread to actually perform synchronous
// (and potentially blocking) syncapi operations.
//
- // Called on the SyncBackendHost core_thread_ to perform initialization
+ // Called on the SyncBackendHost sync_thread_ to perform initialization
// of the syncapi on behalf of SyncBackendHost::Initialize.
void DoInitialize(const DoInitializeOptions& options);
- // Called on our SyncBackendHost's core_thread_ to perform credential
+ // Called on our SyncBackendHost's sync_thread_ to perform credential
// update on behalf of SyncBackendHost::UpdateCredentials
void DoUpdateCredentials(const sync_api::SyncCredentials& credentials);
// Called when the user disables or enables a sync type.
void DoUpdateEnabledTypes();
- // Called on the SyncBackendHost core_thread_ to tell the syncapi to start
+ // Called on the SyncBackendHost sync_thread_ to tell the syncapi to start
// syncing (generally after initialization and authentication).
void DoStartSyncing();
- // Called on the SyncBackendHost core_thread_ to nudge/pause/resume the
+ // Called on the SyncBackendHost sync_thread_ to nudge/pause/resume the
// syncer.
void DoRequestNudge(const tracked_objects::Location& location);
void DoRequestClearServerData();
@@ -361,7 +361,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Sets |deferred_nudge_for_cleanup_requested_| to true. See comment below.
void DeferNudgeForCleanup();
- // Called on our SyncBackendHost's |core_thread_| to set the passphrase
+ // Called on our SyncBackendHost's |sync_thread_| to set the passphrase
// on behalf of SyncBackendHost::SupplyPassphrase.
void DoSetPassphrase(const std::string& passphrase, bool is_explicit);
@@ -371,22 +371,23 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
bool processing_passphrase() const;
void set_processing_passphrase();
- // Called on SyncBackendHost's |core_thread_| to set the datatypes we need
+ // Called on SyncBackendHost's |sync_thread_| to set the datatypes we need
// to encrypt as well as encrypt all local data of that type.
void DoEncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
// The shutdown order is a bit complicated:
- // 1) From |core_thread_|, invoke the syncapi Shutdown call to do a final
- // SaveChanges, close sqlite handles, and halt the syncer thread (which
- // could potentially block for 1 minute).
- // 2) Then, from |frontend_loop_|, halt the core_thread_. This causes
- // syncapi thread-exit handlers to run and make use of cached pointers to
- // various components owned implicitly by us.
- // 3) Destroy this Core. That will delete syncapi components in a safe order
- // because the thread that was using them has exited (in step 2).
+ // 1) From |sync_thread_|, invoke the syncapi Shutdown call to do
+ // a final SaveChanges, and close sqlite handles.
+ // 2) Then, from |frontend_loop_|, halt the sync_thread_ (which is
+ // a blocking call). This causes syncapi thread-exit handlers
+ // to run and make use of cached pointers to various components
+ // owned implicitly by us.
+ // 3) Destroy this Core. That will delete syncapi components in a
+ // safe order because the thread that was using them has exited
+ // (in step 2).
void DoShutdown(bool stopping_sync);
- // Posts a config request on the core thread.
+ // Posts a config request on the sync thread.
virtual void DoRequestConfig(const syncable::ModelTypeBitSet& added_types,
sync_api::ConfigureReason reason);
@@ -444,19 +445,19 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Invoked when initialization of syncapi is complete and we can start
// our timer.
// This must be called from the thread on which SaveChanges is intended to
- // be run on; the host's |core_thread_|.
+ // be run on; the host's |sync_thread_|.
void StartSavingChanges();
// Invoked periodically to tell the syncapi to persist its state
// by writing to disk.
// This is called from the thread we were created on (which is the
- // SyncBackendHost |core_thread_|), using a repeating timer that is kicked
+ // SyncBackendHost |sync_thread_|), using a repeating timer that is kicked
// off as soon as the SyncManager tells us it completed
// initialization.
void SaveChanges();
- // Dispatched to from HandleAuthErrorEventOnCoreLoop to handle updating
- // frontend UI components.
+ // Dispatched to from OnAuthError to handle updating frontend UI
+ // components.
void HandleAuthErrorEventOnFrontendLoop(
const GoogleServiceAuthError& new_auth_error);
@@ -535,7 +536,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// set up initial conditions.
virtual void HandleInitializationCompletedOnFrontendLoop();
- // Posts a nudge request on the core thread.
+ // Posts a nudge request on the sync thread.
virtual void RequestNudge(const tracked_objects::Location& location);
// Called to finish the job of ConfigureDataTypes once the syncer is in
@@ -550,7 +551,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
virtual sync_api::HttpPostProviderFactory* MakeHttpBridgeFactory(
net::URLRequestContextGetter* getter);
- MessageLoop* core_loop() { return core_thread_.message_loop(); }
+ MessageLoop* sync_loop() { return sync_thread_.message_loop(); }
void set_syncapi_initialized() { syncapi_initialized_ = true; }
@@ -599,10 +600,8 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
sync_api::ConfigureReason reason,
bool nigori_enabled);
- // A thread we dedicate for use by our Core to perform initialization,
- // authentication, handle messages from the syncapi, and periodically tell
- // the syncapi to persist itself.
- base::Thread core_thread_;
+ // A thread where all the sync operations happen.
+ base::Thread sync_thread_;
// A reference to the MessageLoop used to construct |this|, so we know how
// to safely talk back to the SyncFrontend.
@@ -629,7 +628,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// The syncapi needs to periodically get a consistent snapshot of the state,
// and it does so from a different thread. Therefore, we protect creation,
// destruction, and re-routing events by acquiring this lock. Note that the
- // SyncBackendHost may read (on the UI thread or core thread) from registrar_
+ // SyncBackendHost may read (on the UI thread or sync thread) from registrar_
// without acquiring the lock (which is typically "read ModelSafeWorker
// pointer value", and then invoke methods), because lifetimes are managed on
// the UI thread. Of course, this comment only applies to ModelSafeWorker
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 9c6010a..7453645 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -79,7 +79,7 @@ sync_api::HttpPostProviderFactory*
void SyncBackendHostForProfileSyncTest::InitCore(
const Core::DoInitializeOptions& options) {
std::wstring user = L"testuser@gmail.com";
- core_loop()->PostTask(
+ sync_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoInitializeForTest,
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 4baab80..8ea46516 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -640,8 +640,8 @@
'browser/sync/engine/syncer_end_command.h',
'browser/sync/engine/syncer_proto_util.cc',
'browser/sync/engine/syncer_proto_util.h',
- 'browser/sync/engine/syncer_thread.cc',
- 'browser/sync/engine/syncer_thread.h',
+ 'browser/sync/engine/sync_scheduler.cc',
+ 'browser/sync/engine/sync_scheduler.h',
'browser/sync/engine/syncer_types.cc',
'browser/sync/engine/syncer_types.h',
'browser/sync/engine/syncer_util.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 79aab3b..752091c 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -3151,8 +3151,8 @@
'browser/sync/engine/process_commit_response_command_unittest.cc',
'browser/sync/engine/syncapi_unittest.cc',
'browser/sync/engine/syncer_proto_util_unittest.cc',
- 'browser/sync/engine/syncer_thread_unittest.cc',
- 'browser/sync/engine/syncer_thread_whitebox_unittest.cc',
+ 'browser/sync/engine/sync_scheduler_unittest.cc',
+ 'browser/sync/engine/sync_scheduler_whitebox_unittest.cc',
'browser/sync/engine/syncer_unittest.cc',
'browser/sync/engine/syncproto_unittest.cc',
'browser/sync/engine/syncapi_mock.h',