| 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 status == SYNC_STATUS_UNKNOWN_ORIGIN || | 56 status == SYNC_STATUS_UNKNOWN_ORIGIN || |
| 57 status == SYNC_STATUS_RETRY; | 57 status == SYNC_STATUS_RETRY; |
| 58 } | 58 } |
| 59 | 59 |
| 60 } // namespace | 60 } // namespace |
| 61 | 61 |
| 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 size_t 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), | 72 service_state_(SYNC_SERVICE_RUNNING), |
| 73 last_delay_(0), | |
| 74 pending_changes_(0), | 73 pending_changes_(0), |
| 75 factory_(this) { | 74 factory_(this) { |
| 76 DCHECK_LE(1, max_parallel_task_); | 75 DCHECK_LE(1u, max_parallel_task_); |
| 77 | |
| 78 DCHECK_EQ(1, max_parallel_task_) | |
| 79 << "Parellel task execution is not yet implemented."; | |
| 80 if (!timer_helper_) | 76 if (!timer_helper_) |
| 81 timer_helper_.reset(new BaseTimerHelper); | 77 timer_helper_.reset(new BaseTimerHelper); |
| 82 } | 78 } |
| 83 | 79 |
| 84 SyncProcessRunner::~SyncProcessRunner() {} | 80 SyncProcessRunner::~SyncProcessRunner() {} |
| 85 | 81 |
| 86 void SyncProcessRunner::Schedule() { | 82 void SyncProcessRunner::Schedule() { |
| 87 int64 delay = kSyncDelayInMilliseconds; | |
| 88 if (pending_changes_ == 0) { | 83 if (pending_changes_ == 0) { |
| 89 ScheduleInternal(kSyncDelayMaxInMilliseconds); | 84 ScheduleInternal(kSyncDelayMaxInMilliseconds); |
| 90 return; | 85 return; |
| 91 } | 86 } |
| 92 switch (GetServiceState()) { | 87 |
| 88 SyncServiceState last_service_state = service_state_; |
| 89 service_state_ = GetServiceState(); |
| 90 |
| 91 switch (service_state_) { |
| 93 case SYNC_SERVICE_RUNNING: | 92 case SYNC_SERVICE_RUNNING: |
| 93 ResetThrottling(); |
| 94 if (pending_changes_ > kPendingChangeThresholdForFastSync) | 94 if (pending_changes_ > kPendingChangeThresholdForFastSync) |
| 95 delay = kSyncDelayFastInMilliseconds; | 95 ScheduleInternal(kSyncDelayFastInMilliseconds); |
| 96 else | 96 else |
| 97 delay = kSyncDelayInMilliseconds; | 97 ScheduleInternal(kSyncDelayInMilliseconds); |
| 98 break; | 98 return; |
| 99 | 99 |
| 100 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE: | 100 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE: |
| 101 delay = kSyncDelaySlowInMilliseconds; | 101 if (last_service_state != service_state_) |
| 102 if (last_delay_ >= kSyncDelaySlowInMilliseconds) | 102 ThrottleSync(kSyncDelaySlowInMilliseconds); |
| 103 delay = last_delay_ * 2; | 103 ScheduleInternal(kSyncDelaySlowInMilliseconds); |
| 104 if (delay >= kSyncDelayMaxInMilliseconds) | 104 return; |
| 105 delay = kSyncDelayMaxInMilliseconds; | |
| 106 break; | |
| 107 | 105 |
| 108 case SYNC_SERVICE_AUTHENTICATION_REQUIRED: | 106 case SYNC_SERVICE_AUTHENTICATION_REQUIRED: |
| 109 case SYNC_SERVICE_DISABLED: | 107 case SYNC_SERVICE_DISABLED: |
| 110 delay = kSyncDelayMaxInMilliseconds; | 108 if (last_service_state != service_state_) |
| 111 break; | 109 ThrottleSync(kSyncDelaySlowInMilliseconds); |
| 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() { |
| 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(); |
| 129 util::Log(logging::LOG_VERBOSE, FROM_HERE, | 156 util::Log(logging::LOG_VERBOSE, FROM_HERE, |
| 130 "[%s] pending_changes updated: %" PRId64, | 157 "[%s] pending_changes updated: %" PRId64, |
| 131 name_.c_str(), pending_changes); | 158 name_.c_str(), pending_changes); |
| 132 } | 159 } |
| 133 Schedule(); | 160 Schedule(); |
| 134 } | 161 } |
| 135 | 162 |
| 136 SyncFileSystemService* SyncProcessRunner::GetSyncService() { | 163 SyncFileSystemService* SyncProcessRunner::GetSyncService() { |
| 137 return client_->GetSyncService(); | 164 return client_->GetSyncService(); |
| 138 } | 165 } |
| 139 | 166 |
| 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(0u, 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 |
| 186 if (WasSuccessfulSync(status)) |
| 187 ResetOldThrottling(); |
| 159 else | 188 else |
| 160 Schedule(); | 189 ThrottleSync(kSyncDelayWithSyncError); |
| 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 base::TimeTicks now = timer_helper_->Now(); |
| 168 last_delay_ = current_delay_; | 199 last_run_ = now; |
| 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 now)); |
| 206 if (running_tasks_ < max_parallel_task_) |
| 207 Schedule(); |
| 175 } | 208 } |
| 176 | 209 |
| 177 void SyncProcessRunner::ScheduleInternal(int64 delay) { | 210 void SyncProcessRunner::ScheduleInternal(int64 delay) { |
| 178 base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay); | 211 base::TimeTicks now = timer_helper_->Now(); |
| 212 base::TimeTicks next_scheduled; |
| 179 | 213 |
| 180 if (timer_helper_->IsRunning()) { | 214 if (timer_helper_->IsRunning()) { |
| 181 if (current_delay_ == delay) | 215 next_scheduled = last_run_ + base::TimeDelta::FromMilliseconds(delay); |
| 182 return; | 216 if (next_scheduled < now) { |
| 183 | 217 next_scheduled = |
| 184 base::TimeDelta elapsed = timer_helper_->Now() - last_scheduled_; | 218 now + base::TimeDelta::FromMilliseconds(kSyncDelayFastInMilliseconds); |
| 185 if (elapsed < time_to_next) { | |
| 186 time_to_next = time_to_next - elapsed; | |
| 187 } else { | |
| 188 time_to_next = base::TimeDelta::FromMilliseconds( | |
| 189 kSyncDelayFastInMilliseconds); | |
| 190 } | 219 } |
| 220 } else { |
| 221 next_scheduled = now + base::TimeDelta::FromMilliseconds(delay); |
| 191 } | 222 } |
| 192 | 223 |
| 193 if (current_delay_ != delay) { | 224 if (next_scheduled < throttle_until_) |
| 194 util::Log(logging::LOG_VERBOSE, FROM_HERE, | 225 next_scheduled = throttle_until_; |
| 195 "[%s] Scheduling task in %" PRId64 " secs", | 226 |
| 196 name_.c_str(), time_to_next.InSeconds()); | 227 if (timer_helper_->IsRunning() && last_scheduled_ == next_scheduled) |
| 197 } | 228 return; |
| 198 current_delay_ = delay; | 229 |
| 230 util::Log(logging::LOG_VERBOSE, FROM_HERE, |
| 231 "[%s] Scheduling task in %" PRId64 " ms", |
| 232 name_.c_str(), (next_scheduled - now).InMilliseconds()); |
| 233 |
| 234 last_scheduled_ = next_scheduled; |
| 199 | 235 |
| 200 timer_helper_->Start( | 236 timer_helper_->Start( |
| 201 FROM_HERE, time_to_next, | 237 FROM_HERE, next_scheduled - now, |
| 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 |