ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / sync_file_system / sync_process_runner.cc
blob748d21a6d02a260760d0dd474eee96888c6ecf52
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/sync_process_runner.h"
7 #include "base/format_macros.h"
8 #include "chrome/browser/sync_file_system/logger.h"
10 namespace sync_file_system {
12 const int64 SyncProcessRunner::kSyncDelayInMilliseconds =
13 1 * base::Time::kMillisecondsPerSecond; // 1 sec
14 const int64 SyncProcessRunner::kSyncDelayWithSyncError =
15 3 * base::Time::kMillisecondsPerSecond; // 3 sec
16 const int64 SyncProcessRunner::kSyncDelayFastInMilliseconds = 100; // 100 ms
17 const int SyncProcessRunner::kPendingChangeThresholdForFastSync = 10;
18 const int64 SyncProcessRunner::kSyncDelaySlowInMilliseconds =
19 30 * base::Time::kMillisecondsPerSecond; // 30 sec
20 const int64 SyncProcessRunner::kSyncDelayMaxInMilliseconds =
21 30 * 60 * base::Time::kMillisecondsPerSecond; // 30 min
23 namespace {
25 class BaseTimerHelper : public SyncProcessRunner::TimerHelper {
26 public:
27 BaseTimerHelper() {}
29 bool IsRunning() override { return timer_.IsRunning(); }
31 void Start(const tracked_objects::Location& from_here,
32 const base::TimeDelta& delay,
33 const base::Closure& closure) override {
34 timer_.Start(from_here, delay, closure);
37 base::TimeTicks Now() const override { return base::TimeTicks::Now(); }
39 ~BaseTimerHelper() override {}
41 private:
42 base::OneShotTimer<SyncProcessRunner> timer_;
44 DISALLOW_COPY_AND_ASSIGN(BaseTimerHelper);
47 bool WasSuccessfulSync(SyncStatusCode status) {
48 return status == SYNC_STATUS_OK ||
49 status == SYNC_STATUS_HAS_CONFLICT ||
50 status == SYNC_STATUS_NO_CONFLICT ||
51 status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
52 status == SYNC_STATUS_UNKNOWN_ORIGIN ||
53 status == SYNC_STATUS_RETRY;
56 } // namespace
58 SyncProcessRunner::SyncProcessRunner(
59 const std::string& name,
60 Client* client,
61 scoped_ptr<TimerHelper> timer_helper,
62 size_t max_parallel_task)
63 : name_(name),
64 client_(client),
65 max_parallel_task_(max_parallel_task),
66 running_tasks_(0),
67 timer_helper_(timer_helper.Pass()),
68 service_state_(SYNC_SERVICE_RUNNING),
69 pending_changes_(0),
70 factory_(this) {
71 DCHECK_LE(1u, max_parallel_task_);
72 if (!timer_helper_)
73 timer_helper_.reset(new BaseTimerHelper);
76 SyncProcessRunner::~SyncProcessRunner() {}
78 void SyncProcessRunner::Schedule() {
79 if (pending_changes_ == 0) {
80 ScheduleInternal(kSyncDelayMaxInMilliseconds);
81 return;
84 SyncServiceState last_service_state = service_state_;
85 service_state_ = GetServiceState();
87 switch (service_state_) {
88 case SYNC_SERVICE_RUNNING:
89 ResetThrottling();
90 if (pending_changes_ > kPendingChangeThresholdForFastSync)
91 ScheduleInternal(kSyncDelayFastInMilliseconds);
92 else
93 ScheduleInternal(kSyncDelayInMilliseconds);
94 return;
96 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE:
97 if (last_service_state != service_state_)
98 ThrottleSync(kSyncDelaySlowInMilliseconds);
99 ScheduleInternal(kSyncDelaySlowInMilliseconds);
100 return;
102 case SYNC_SERVICE_AUTHENTICATION_REQUIRED:
103 case SYNC_SERVICE_DISABLED:
104 if (last_service_state != service_state_)
105 ThrottleSync(kSyncDelaySlowInMilliseconds);
106 ScheduleInternal(kSyncDelayMaxInMilliseconds);
107 return;
110 NOTREACHED();
111 ScheduleInternal(kSyncDelayMaxInMilliseconds);
114 void SyncProcessRunner::ThrottleSync(int64 base_delay) {
115 base::TimeTicks now = timer_helper_->Now();
116 base::TimeDelta elapsed = std::min(now, throttle_until_) - throttle_from_;
117 DCHECK(base::TimeDelta() <= elapsed);
119 throttle_from_ = now;
120 // Extend throttling duration by twice the elapsed time.
121 // That is, if the backoff repeats in a short period, the throttling period
122 // doesn't grow exponentially. If the backoff happens on the end of
123 // throttling period, it causes another throttling period that is twice as
124 // long as previous.
125 base::TimeDelta base_delay_delta =
126 base::TimeDelta::FromMilliseconds(base_delay);
127 const base::TimeDelta max_delay =
128 base::TimeDelta::FromMilliseconds(kSyncDelayMaxInMilliseconds);
129 throttle_until_ =
130 std::min(now + max_delay,
131 std::max(now + base_delay_delta, throttle_until_ + 2 * elapsed));
134 void SyncProcessRunner::ResetOldThrottling() {
135 if (throttle_until_ < base::TimeTicks::Now())
136 ResetThrottling();
139 void SyncProcessRunner::ResetThrottling() {
140 throttle_from_ = base::TimeTicks();
141 throttle_until_ = base::TimeTicks();
144 SyncServiceState SyncProcessRunner::GetServiceState() {
145 return client_->GetSyncServiceState();
148 void SyncProcessRunner::OnChangesUpdated(
149 int64 pending_changes) {
150 DCHECK_GE(pending_changes, 0);
151 int64 old_pending_changes = pending_changes_;
152 pending_changes_ = pending_changes;
153 if (old_pending_changes != pending_changes) {
154 CheckIfIdle();
155 util::Log(logging::LOG_VERBOSE, FROM_HERE,
156 "[%s] pending_changes updated: %" PRId64,
157 name_.c_str(), pending_changes);
159 Schedule();
162 SyncFileSystemService* SyncProcessRunner::GetSyncService() {
163 return client_->GetSyncService();
166 void SyncProcessRunner::Finished(const base::TimeTicks& start_time,
167 SyncStatusCode status) {
168 DCHECK_LT(0u, running_tasks_);
169 DCHECK_LE(running_tasks_, max_parallel_task_);
170 --running_tasks_;
171 CheckIfIdle();
172 util::Log(logging::LOG_VERBOSE, FROM_HERE,
173 "[%s] * Finished (elapsed: %" PRId64 " ms)", name_.c_str(),
174 (timer_helper_->Now() - start_time).InMilliseconds());
176 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
177 status == SYNC_STATUS_FILE_BUSY) {
178 ScheduleInternal(kSyncDelayMaxInMilliseconds);
179 return;
182 if (WasSuccessfulSync(status))
183 ResetOldThrottling();
184 else
185 ThrottleSync(kSyncDelayWithSyncError);
187 Schedule();
190 void SyncProcessRunner::Run() {
191 if (running_tasks_ >= max_parallel_task_)
192 return;
193 ++running_tasks_;
194 base::TimeTicks now = timer_helper_->Now();
195 last_run_ = now;
197 util::Log(logging::LOG_VERBOSE, FROM_HERE,
198 "[%s] * Started", name_.c_str());
200 StartSync(base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr(),
201 now));
202 if (running_tasks_ < max_parallel_task_)
203 Schedule();
206 void SyncProcessRunner::ScheduleInternal(int64 delay) {
207 base::TimeTicks now = timer_helper_->Now();
208 base::TimeTicks next_scheduled;
210 if (timer_helper_->IsRunning()) {
211 next_scheduled = last_run_ + base::TimeDelta::FromMilliseconds(delay);
212 if (next_scheduled < now) {
213 next_scheduled =
214 now + base::TimeDelta::FromMilliseconds(kSyncDelayFastInMilliseconds);
216 } else {
217 next_scheduled = now + base::TimeDelta::FromMilliseconds(delay);
220 if (next_scheduled < throttle_until_)
221 next_scheduled = throttle_until_;
223 if (timer_helper_->IsRunning() && last_scheduled_ == next_scheduled)
224 return;
226 util::Log(logging::LOG_VERBOSE, FROM_HERE,
227 "[%s] Scheduling task in %" PRId64 " ms",
228 name_.c_str(), (next_scheduled - now).InMilliseconds());
230 last_scheduled_ = next_scheduled;
232 timer_helper_->Start(
233 FROM_HERE, next_scheduled - now,
234 base::Bind(&SyncProcessRunner::Run, base::Unretained(this)));
237 void SyncProcessRunner::CheckIfIdle() {
238 if (pending_changes_ == 0 && running_tasks_ == 0)
239 client_->OnSyncIdle();
242 } // namespace sync_file_system