OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync_file_system/sync_process_runner.h" | 5 #include "chrome/browser/sync_file_system/sync_process_runner.h" |
6 | 6 |
7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
8 #include "chrome/browser/sync_file_system/logger.h" | 8 #include "chrome/browser/sync_file_system/logger.h" |
9 | 9 |
10 namespace sync_file_system { | 10 namespace sync_file_system { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
62 SyncProcessRunner::SyncProcessRunner( | 62 SyncProcessRunner::SyncProcessRunner( |
63 const std::string& name, | 63 const std::string& name, |
64 Client* client, | 64 Client* client, |
65 scoped_ptr<TimerHelper> timer_helper, | 65 scoped_ptr<TimerHelper> timer_helper, |
66 int max_parallel_task) | 66 int max_parallel_task) |
67 : name_(name), | 67 : name_(name), |
68 client_(client), | 68 client_(client), |
69 max_parallel_task_(max_parallel_task), | 69 max_parallel_task_(max_parallel_task), |
70 running_tasks_(0), | 70 running_tasks_(0), |
71 timer_helper_(timer_helper.Pass()), | 71 timer_helper_(timer_helper.Pass()), |
72 current_delay_(0), | |
73 last_delay_(0), | |
74 pending_changes_(0), | 72 pending_changes_(0), |
75 factory_(this) { | 73 factory_(this) { |
76 DCHECK_LE(1, max_parallel_task_); | 74 DCHECK_LE(1, max_parallel_task_); |
77 | 75 |
78 DCHECK_EQ(1, max_parallel_task_) | 76 DCHECK_EQ(1, max_parallel_task_) |
79 << "Parellel task execution is not yet implemented."; | 77 << "Parellel task execution is not yet implemented."; |
80 if (!timer_helper_) | 78 if (!timer_helper_) |
81 timer_helper_.reset(new BaseTimerHelper); | 79 timer_helper_.reset(new BaseTimerHelper); |
82 } | 80 } |
83 | 81 |
84 SyncProcessRunner::~SyncProcessRunner() {} | 82 SyncProcessRunner::~SyncProcessRunner() {} |
85 | 83 |
86 void SyncProcessRunner::Schedule() { | 84 void SyncProcessRunner::Schedule() { |
85 if (running_tasks_ >= max_parallel_task_) | |
86 return; | |
87 | |
87 int64 delay = kSyncDelayInMilliseconds; | 88 int64 delay = kSyncDelayInMilliseconds; |
88 if (pending_changes_ == 0) { | 89 if (pending_changes_ == 0) { |
89 ScheduleInternal(kSyncDelayMaxInMilliseconds); | 90 ScheduleInternal(kSyncDelayMaxInMilliseconds); |
90 return; | 91 return; |
91 } | 92 } |
92 switch (GetServiceState()) { | 93 switch (GetServiceState()) { |
93 case SYNC_SERVICE_RUNNING: | 94 case SYNC_SERVICE_RUNNING: |
95 ResetThrottling(); | |
94 if (pending_changes_ > kPendingChangeThresholdForFastSync) | 96 if (pending_changes_ > kPendingChangeThresholdForFastSync) |
95 delay = kSyncDelayFastInMilliseconds; | 97 ScheduleInternal(kSyncDelayFastInMilliseconds); |
96 else | 98 else |
97 delay = kSyncDelayInMilliseconds; | 99 ScheduleInternal(kSyncDelayInMilliseconds); |
98 break; | 100 return; |
99 | 101 |
100 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE: | 102 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE: |
101 delay = kSyncDelaySlowInMilliseconds; | 103 ThrottleSync(kSyncDelaySlowInMilliseconds); |
102 if (last_delay_ >= kSyncDelaySlowInMilliseconds) | 104 ScheduleInternal(kSyncDelaySlowInMilliseconds); |
103 delay = last_delay_ * 2; | 105 return; |
104 if (delay >= kSyncDelayMaxInMilliseconds) | |
105 delay = kSyncDelayMaxInMilliseconds; | |
106 break; | |
107 | 106 |
108 case SYNC_SERVICE_AUTHENTICATION_REQUIRED: | 107 case SYNC_SERVICE_AUTHENTICATION_REQUIRED: |
109 case SYNC_SERVICE_DISABLED: | 108 case SYNC_SERVICE_DISABLED: |
110 delay = kSyncDelayMaxInMilliseconds; | 109 ThrottleSync(kSyncDelaySlowInMilliseconds); |
111 break; | 110 ScheduleInternal(kSyncDelayMaxInMilliseconds); |
111 return; | |
112 } | 112 } |
113 ScheduleInternal(delay); | 113 |
114 NOTREACHED(); | |
115 ScheduleInternal(kSyncDelayMaxInMilliseconds); | |
114 } | 116 } |
115 | 117 |
116 void SyncProcessRunner::ScheduleIfNotRunning() { | 118 void SyncProcessRunner::ThrottleSync(int64 base_delay) { |
117 if (!timer_helper_->IsRunning()) | 119 base::TimeTicks now = timer_helper_->Now(); |
118 Schedule(); | 120 base::TimeDelta elapsed = std::min(now, throttle_until_) - throttle_from_; |
121 DCHECK(base::TimeDelta() <= elapsed); | |
122 | |
123 throttle_from_ = now; | |
124 // Extend throttling duration by twice the elapsed time. | |
125 // That is, if the backoff repeats in a short period, the throttling period | |
126 // doesn't grow exponentially. If the backoff happens on the end of | |
127 // throttling period, it causes another throttling period that is twice as | |
128 // long as previous. | |
129 base::TimeDelta base_delay_delta = | |
130 base::TimeDelta::FromMilliseconds(base_delay); | |
131 const base::TimeDelta max_delay = | |
132 base::TimeDelta::FromMilliseconds(kSyncDelayMaxInMilliseconds); | |
133 throttle_until_ = | |
134 std::min(now + max_delay, | |
135 std::max(now + base_delay_delta, throttle_until_ + 2 * elapsed)); | |
136 } | |
137 | |
138 void SyncProcessRunner::ResetOldThrottling() { | |
nhiroki
2014/07/10 08:17:21
This is not used in this CL.
tzik
2014/07/11 06:00:48
I forgot to call this. Now it's used in Finished()
| |
139 if (throttle_until_ < base::TimeTicks::Now()) | |
140 ResetThrottling(); | |
141 } | |
142 | |
143 void SyncProcessRunner::ResetThrottling() { | |
144 throttle_from_ = base::TimeTicks(); | |
145 throttle_until_ = base::TimeTicks(); | |
119 } | 146 } |
120 | 147 |
121 void SyncProcessRunner::OnChangesUpdated( | 148 void SyncProcessRunner::OnChangesUpdated( |
122 int64 pending_changes) { | 149 int64 pending_changes) { |
123 DCHECK_GE(pending_changes, 0); | 150 DCHECK_GE(pending_changes, 0); |
124 int64 old_pending_changes = pending_changes_; | 151 int64 old_pending_changes = pending_changes_; |
125 pending_changes_ = pending_changes; | 152 pending_changes_ = pending_changes; |
126 if (old_pending_changes != pending_changes) { | 153 if (old_pending_changes != pending_changes) { |
127 if (pending_changes == 0) | 154 if (pending_changes == 0) |
128 client_->OnSyncIdle(); | 155 client_->OnSyncIdle(); |
(...skipping 11 matching lines...) Expand all Loading... | |
140 SyncServiceState SyncProcessRunner::GetServiceState() { | 167 SyncServiceState SyncProcessRunner::GetServiceState() { |
141 return client_->GetSyncServiceState(); | 168 return client_->GetSyncServiceState(); |
142 } | 169 } |
143 | 170 |
144 void SyncProcessRunner::Finished(const base::TimeTicks& start_time, | 171 void SyncProcessRunner::Finished(const base::TimeTicks& start_time, |
145 SyncStatusCode status) { | 172 SyncStatusCode status) { |
146 DCHECK_LT(0, running_tasks_); | 173 DCHECK_LT(0, running_tasks_); |
147 DCHECK_LE(running_tasks_, max_parallel_task_); | 174 DCHECK_LE(running_tasks_, max_parallel_task_); |
148 --running_tasks_; | 175 --running_tasks_; |
149 util::Log(logging::LOG_VERBOSE, FROM_HERE, | 176 util::Log(logging::LOG_VERBOSE, FROM_HERE, |
150 "[%s] * Finished (elapsed: %" PRId64 " sec)", | 177 "[%s] * Finished (elapsed: %" PRId64 " ms)", name_.c_str(), |
151 name_.c_str(), | 178 (timer_helper_->Now() - start_time).InMilliseconds()); |
152 (timer_helper_->Now() - start_time).InSeconds()); | 179 |
153 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC || | 180 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC || |
154 status == SYNC_STATUS_FILE_BUSY) | 181 status == SYNC_STATUS_FILE_BUSY) { |
155 ScheduleInternal(kSyncDelayMaxInMilliseconds); | 182 ScheduleInternal(kSyncDelayMaxInMilliseconds); |
156 else if (!WasSuccessfulSync(status) && | 183 return; |
157 GetServiceState() == SYNC_SERVICE_RUNNING) | 184 } |
158 ScheduleInternal(kSyncDelayWithSyncError); | 185 |
159 else | 186 if (!WasSuccessfulSync(status) && |
160 Schedule(); | 187 GetServiceState() == SYNC_SERVICE_RUNNING) { |
188 ThrottleSync(kSyncDelayWithSyncError); | |
189 } | |
190 | |
191 Schedule(); | |
161 } | 192 } |
162 | 193 |
163 void SyncProcessRunner::Run() { | 194 void SyncProcessRunner::Run() { |
164 if (running_tasks_ >= max_parallel_task_) | 195 if (running_tasks_ >= max_parallel_task_) |
165 return; | 196 return; |
166 ++running_tasks_; | 197 ++running_tasks_; |
167 last_scheduled_ = timer_helper_->Now(); | 198 last_scheduled_ = timer_helper_->Now(); |
168 last_delay_ = current_delay_; | 199 last_delay_ = current_delay_; |
169 | 200 |
170 util::Log(logging::LOG_VERBOSE, FROM_HERE, | 201 util::Log(logging::LOG_VERBOSE, FROM_HERE, |
171 "[%s] * Started", name_.c_str()); | 202 "[%s] * Started", name_.c_str()); |
172 | 203 |
173 StartSync(base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr(), | 204 StartSync(base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr(), |
174 last_scheduled_)); | 205 last_scheduled_)); |
206 Schedule(); | |
175 } | 207 } |
176 | 208 |
177 void SyncProcessRunner::ScheduleInternal(int64 delay) { | 209 void SyncProcessRunner::ScheduleInternal(int64 delay) { |
178 base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay); | 210 base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay); |
211 base::TimeTicks now = timer_helper_->Now(); | |
179 | 212 |
180 if (timer_helper_->IsRunning()) { | 213 if (timer_helper_->IsRunning()) { |
181 if (current_delay_ == delay) | 214 if (current_delay_ == delay) |
182 return; | 215 return; |
183 | 216 |
184 base::TimeDelta elapsed = timer_helper_->Now() - last_scheduled_; | 217 base::TimeDelta elapsed = now - last_scheduled_; |
185 if (elapsed < time_to_next) { | 218 if (elapsed < time_to_next) { |
186 time_to_next = time_to_next - elapsed; | 219 time_to_next = time_to_next - elapsed; |
187 } else { | 220 } else { |
188 time_to_next = base::TimeDelta::FromMilliseconds( | 221 time_to_next = base::TimeDelta::FromMilliseconds( |
189 kSyncDelayFastInMilliseconds); | 222 kSyncDelayFastInMilliseconds); |
190 } | 223 } |
191 } | 224 } |
192 | 225 |
226 if (now + time_to_next < throttle_until_) | |
227 time_to_next = throttle_until_ - now; | |
228 | |
193 if (current_delay_ != delay) { | 229 if (current_delay_ != delay) { |
194 util::Log(logging::LOG_VERBOSE, FROM_HERE, | 230 util::Log(logging::LOG_VERBOSE, FROM_HERE, |
195 "[%s] Scheduling task in %" PRId64 " secs", | 231 "[%s] Scheduling task in %" PRId64 " secs", |
196 name_.c_str(), time_to_next.InSeconds()); | 232 name_.c_str(), time_to_next.InSeconds()); |
197 } | 233 } |
198 current_delay_ = delay; | 234 current_delay_ = delay; |
199 | 235 |
200 timer_helper_->Start( | 236 timer_helper_->Start( |
201 FROM_HERE, time_to_next, | 237 FROM_HERE, time_to_next, |
202 base::Bind(&SyncProcessRunner::Run, base::Unretained(this))); | 238 base::Bind(&SyncProcessRunner::Run, base::Unretained(this))); |
203 } | 239 } |
204 | 240 |
205 } // namespace sync_file_system | 241 } // namespace sync_file_system |
OLD | NEW |