#ifndef SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
#define SYNC_ENGINE_SYNC_SCHEDULER_IMPL_H_
#include <map>
#include <string>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time.h"
#include "base/timer.h"
#include "sync/engine/net/server_connection_manager.h"
#include "sync/engine/nudge_source.h"
#include "sync/engine/sync_scheduler.h"
#include "sync/engine/syncer.h"
#include "sync/internal_api/public/base/model_type_state_map.h"
#include "sync/internal_api/public/engine/polling_constants.h"
#include "sync/internal_api/public/util/weak_handle.h"
#include "sync/sessions/sync_session.h"
#include "sync/sessions/sync_session_context.h"
namespace syncer {
class BackoffDelayProvider;
class SyncSchedulerImpl : public SyncScheduler {
public:
SyncSchedulerImpl(const std::string& name,
BackoffDelayProvider* delay_provider,
sessions::SyncSessionContext* context,
Syncer* syncer);
virtual ~SyncSchedulerImpl();
virtual void Start(Mode mode) OVERRIDE;
virtual bool ScheduleConfiguration(
const ConfigurationParams& params) OVERRIDE;
virtual void RequestStop(const base::Closure& callback) OVERRIDE;
virtual void ScheduleNudgeAsync(
const base::TimeDelta& delay,
NudgeSource source,
ModelTypeSet types,
const tracked_objects::Location& nudge_location) OVERRIDE;
virtual void ScheduleNudgeWithStatesAsync(
const base::TimeDelta& delay, NudgeSource source,
const ModelTypeStateMap& type_state_map,
const tracked_objects::Location& nudge_location) OVERRIDE;
virtual void SetNotificationsEnabled(bool notifications_enabled) OVERRIDE;
virtual base::TimeDelta GetSessionsCommitDelay() const OVERRIDE;
virtual void OnCredentialsUpdated() OVERRIDE;
virtual void OnConnectionStatusChange() OVERRIDE;
virtual void OnSilencedUntil(
const base::TimeTicks& silenced_until) OVERRIDE;
virtual bool IsSyncingCurrentlySilenced() OVERRIDE;
virtual void OnReceivedShortPollIntervalUpdate(
const base::TimeDelta& new_interval) OVERRIDE;
virtual void OnReceivedLongPollIntervalUpdate(
const base::TimeDelta& new_interval) OVERRIDE;
virtual void OnReceivedSessionsCommitDelay(
const base::TimeDelta& new_delay) OVERRIDE;
virtual void OnShouldStopSyncingPermanently() OVERRIDE;
virtual void OnSyncProtocolError(
const sessions::SyncSessionSnapshot& snapshot) OVERRIDE;
private:
enum JobProcessDecision {
CONTINUE,
SAVE,
DROP,
};
struct SyncSessionJob {
enum SyncSessionJobPurpose {
UNKNOWN = -1,
POLL,
NUDGE,
CONFIGURATION,
};
SyncSessionJob();
SyncSessionJob(SyncSessionJobPurpose purpose, base::TimeTicks start,
linked_ptr<sessions::SyncSession> session, bool is_canary_job,
const ConfigurationParams& config_params,
const tracked_objects::Location& nudge_location);
~SyncSessionJob();
static const char* GetPurposeString(SyncSessionJobPurpose purpose);
SyncSessionJobPurpose purpose;
base::TimeTicks scheduled_start;
linked_ptr<sessions::SyncSession> session;
bool is_canary_job;
ConfigurationParams config_params;
tracked_objects::Location from_here;
};
friend class SyncSchedulerTest;
friend class SyncSchedulerWhiteboxTest;
friend class SyncerTest;
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
DropNudgeWhileExponentialBackOff);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest, SaveNudge);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
SaveNudgeWhileTypeThrottled);
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(SyncSchedulerWhiteboxTest,
SaveNudgeWhileThrottled);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
ContinueCanaryJobConfig);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerWhiteboxTest,
ContinueNudgeWhileExponentialBackOff);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, TransientPollFailure);
FRIEND_TEST_ALL_PREFIXES(SyncSchedulerTest, GetInitialBackoffDelay);
struct WaitInterval {
enum Mode {
UNKNOWN = -1,
EXPONENTIAL_BACKOFF,
THROTTLED,
};
WaitInterval();
~WaitInterval();
WaitInterval(Mode mode, base::TimeDelta length);
static const char* GetModeString(Mode mode);
Mode mode;
bool had_nudge;
base::TimeDelta length;
base::OneShotTimer<SyncSchedulerImpl> timer;
scoped_ptr<SyncSessionJob> pending_configure_job;
};
static const char* GetModeString(Mode mode);
static const char* GetDecisionString(JobProcessDecision decision);
static void SetSyncerStepsForPurpose(
SyncSessionJob::SyncSessionJobPurpose purpose,
SyncerStep* start, SyncerStep* end);
void PostTask(const tracked_objects::Location& from_here,
const char* name,
const base::Closure& task);
void PostDelayedTask(const tracked_objects::Location& from_here,
const char* name,
const base::Closure& task,
base::TimeDelta delay);
void ScheduleSyncSessionJob(const SyncSessionJob& job);
void DoSyncSessionJob(const SyncSessionJob& job);
void FinishSyncSessionJob(const SyncSessionJob& job);
void ScheduleNextSync(const SyncSessionJob& old_job);
void AdjustPolling(const SyncSessionJob* old_job);
void RestartWaiting();
void HandleContinuationError(const SyncSessionJob& old_job);
bool ShouldRunJob(const SyncSessionJob& job);
JobProcessDecision DecideOnJob(const SyncSessionJob& job);
JobProcessDecision DecideWhileInWaitInterval(const SyncSessionJob& job);
void SaveJob(const SyncSessionJob& job);
void InitOrCoalescePendingJob(const SyncSessionJob& job);
void StopImpl(const base::Closure& callback);
void ScheduleNudgeImpl(
const base::TimeDelta& delay,
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
const ModelTypeStateMap& type_state_map,
bool is_canary_job, const tracked_objects::Location& nudge_location);
bool IsBackingOff() const;
void Notify(SyncEngineEvent::EventCause cause);
void DoCanaryJob();
void Unthrottle();
void DoPendingJobIfPossible(bool is_canary_job);
void OnServerConnectionErrorFixed();
sessions::SyncSession* CreateSyncSession(
const sessions::SyncSourceInfo& info);
void PollTimerCallback();
void UpdateServerConnectionManagerStatus(
HttpResponse::ServerConnectionCode code);
void SendInitialSnapshot();
void UpdateNudgeTimeRecords(const sessions::SyncSourceInfo& info);
virtual void OnActionableError(const sessions::SyncSessionSnapshot& snapshot);
base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_;
base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_for_weak_handle_;
const WeakHandle<SyncSchedulerImpl> weak_handle_this_;
const std::string name_;
MessageLoop* const sync_loop_;
bool started_;
base::TimeDelta syncer_short_poll_interval_seconds_;
base::TimeDelta syncer_long_poll_interval_seconds_;
base::TimeDelta sessions_commit_delay_;
base::RepeatingTimer<SyncSchedulerImpl> poll_timer_;
Mode mode_;
HttpResponse::ServerConnectionCode connection_code_;
scoped_ptr<SyncSessionJob> pending_nudge_;
scoped_ptr<WaitInterval> wait_interval_;
scoped_ptr<BackoffDelayProvider> delay_provider_;
scoped_ptr<Syncer> syncer_;
sessions::SyncSessionContext* session_context_;
typedef std::map<ModelType, base::TimeTicks> ModelTypeTimeMap;
ModelTypeTimeMap last_local_nudges_by_model_type_;
bool no_scheduling_allowed_;
DISALLOW_COPY_AND_ASSIGN(SyncSchedulerImpl);
};
}
#endif