Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / sync_process_runner.cc
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.
4
5 #include "chrome/browser/sync_file_system/sync_process_runner.h"
6
7 #include "base/format_macros.h"
8 #include "chrome/browser/sync_file_system/logger.h"
9
10 namespace sync_file_system {
11
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
22
23 namespace {
24
25 class BaseTimerHelper : public SyncProcessRunner::TimerHelper {
26  public:
27   BaseTimerHelper() {}
28
29   bool IsRunning() override { return timer_.IsRunning(); }
30
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);
35   }
36
37   base::TimeTicks Now() const override { return base::TimeTicks::Now(); }
38
39   ~BaseTimerHelper() override {}
40
41  private:
42   base::OneShotTimer<SyncProcessRunner> timer_;
43
44   DISALLOW_COPY_AND_ASSIGN(BaseTimerHelper);
45 };
46
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;
54 }
55
56 }  // namespace
57
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);
74 }
75
76 SyncProcessRunner::~SyncProcessRunner() {}
77
78 void SyncProcessRunner::Schedule() {
79   if (pending_changes_ == 0) {
80     ScheduleInternal(kSyncDelayMaxInMilliseconds);
81     return;
82   }
83
84   SyncServiceState last_service_state = service_state_;
85   service_state_ = GetServiceState();
86
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;
95
96     case SYNC_SERVICE_TEMPORARY_UNAVAILABLE:
97       if (last_service_state != service_state_)
98         ThrottleSync(kSyncDelaySlowInMilliseconds);
99       ScheduleInternal(kSyncDelaySlowInMilliseconds);
100       return;
101
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;
108   }
109
110   NOTREACHED();
111   ScheduleInternal(kSyncDelayMaxInMilliseconds);
112 }
113
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);
118
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));
132 }
133
134 void SyncProcessRunner::ResetOldThrottling() {
135   if (throttle_until_ < base::TimeTicks::Now())
136     ResetThrottling();
137 }
138
139 void SyncProcessRunner::ResetThrottling() {
140   throttle_from_ = base::TimeTicks();
141   throttle_until_ = base::TimeTicks();
142 }
143
144 SyncServiceState SyncProcessRunner::GetServiceState() {
145   return client_->GetSyncServiceState();
146 }
147
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);
158   }
159   Schedule();
160 }
161
162 SyncFileSystemService* SyncProcessRunner::GetSyncService() {
163   return client_->GetSyncService();
164 }
165
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());
175
176   if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
177       status == SYNC_STATUS_FILE_BUSY) {
178     ScheduleInternal(kSyncDelayMaxInMilliseconds);
179     return;
180   }
181
182   if (WasSuccessfulSync(status))
183     ResetOldThrottling();
184   else
185     ThrottleSync(kSyncDelayWithSyncError);
186
187   Schedule();
188 }
189
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;
196
197   util::Log(logging::LOG_VERBOSE, FROM_HERE,
198             "[%s] * Started", name_.c_str());
199
200   StartSync(base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr(),
201                        now));
202   if (running_tasks_ < max_parallel_task_)
203     Schedule();
204 }
205
206 void SyncProcessRunner::ScheduleInternal(int64 delay) {
207   base::TimeTicks now = timer_helper_->Now();
208   base::TimeTicks next_scheduled;
209
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);
215     }
216   } else {
217     next_scheduled = now + base::TimeDelta::FromMilliseconds(delay);
218   }
219
220   if (next_scheduled < throttle_until_)
221     next_scheduled = throttle_until_;
222
223   if (timer_helper_->IsRunning() && last_scheduled_ == next_scheduled)
224     return;
225
226   util::Log(logging::LOG_VERBOSE, FROM_HERE,
227             "[%s] Scheduling task in %" PRId64 " ms",
228             name_.c_str(), (next_scheduled - now).InMilliseconds());
229
230   last_scheduled_ = next_scheduled;
231
232   timer_helper_->Start(
233       FROM_HERE, next_scheduled - now,
234       base::Bind(&SyncProcessRunner::Run, base::Unretained(this)));
235 }
236
237 void SyncProcessRunner::CheckIfIdle() {
238   if (pending_changes_ == 0 && running_tasks_ == 0)
239     client_->OnSyncIdle();
240 }
241
242 }  // namespace sync_file_system