sync_process_runner.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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#include "chrome/browser/sync_file_system/sync_file_system_service.h" 10 11namespace sync_file_system { 12 13namespace { 14 15// Default delay when more changes are available. 16const int64 kSyncDelayInMilliseconds = 1 * base::Time::kMillisecondsPerSecond; 17 18// Default delay when the previous change has had an error (but remote service 19// is running). 20const int64 kSyncDelayWithSyncError = 3 * base::Time::kMillisecondsPerSecond; 21 22// Default delay when there're more than 10 pending changes. 23const int64 kSyncDelayFastInMilliseconds = 100; 24const int kPendingChangeThresholdForFastSync = 10; 25 26// Default delay when remote service is temporarily unavailable. 27const int64 kSyncDelaySlowInMilliseconds = 28 30 * base::Time::kMillisecondsPerSecond; // Start with 30 sec + exp backoff 29 30// Default delay when there're no changes. 31const int64 kSyncDelayMaxInMilliseconds = 32 30 * 60 * base::Time::kMillisecondsPerSecond; // 30 min 33 34bool WasSuccessfulSync(SyncStatusCode status) { 35 return status == SYNC_STATUS_OK || 36 status == SYNC_STATUS_HAS_CONFLICT || 37 status == SYNC_STATUS_NO_CONFLICT || 38 status == SYNC_STATUS_NO_CHANGE_TO_SYNC || 39 status == SYNC_STATUS_UNKNOWN_ORIGIN || 40 status == SYNC_STATUS_RETRY; 41} 42 43} // namespace 44 45SyncProcessRunner::SyncProcessRunner( 46 const std::string& name, 47 SyncFileSystemService* sync_service) 48 : name_(name), 49 sync_service_(sync_service), 50 current_delay_(0), 51 last_delay_(0), 52 pending_changes_(0), 53 running_(false), 54 factory_(this) {} 55 56SyncProcessRunner::~SyncProcessRunner() {} 57 58void SyncProcessRunner::Schedule() { 59 int64 delay = kSyncDelayInMilliseconds; 60 if (pending_changes_ == 0) { 61 ScheduleInternal(kSyncDelayMaxInMilliseconds); 62 return; 63 } 64 switch (GetServiceState()) { 65 case SYNC_SERVICE_RUNNING: 66 if (pending_changes_ > kPendingChangeThresholdForFastSync) 67 delay = kSyncDelayFastInMilliseconds; 68 else 69 delay = kSyncDelayInMilliseconds; 70 break; 71 72 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE: 73 delay = kSyncDelaySlowInMilliseconds; 74 if (last_delay_ >= kSyncDelaySlowInMilliseconds) 75 delay = last_delay_ * 2; 76 if (delay >= kSyncDelayMaxInMilliseconds) 77 delay = kSyncDelayMaxInMilliseconds; 78 break; 79 80 case SYNC_SERVICE_AUTHENTICATION_REQUIRED: 81 case SYNC_SERVICE_DISABLED: 82 delay = kSyncDelayMaxInMilliseconds; 83 break; 84 } 85 ScheduleInternal(delay); 86} 87 88void SyncProcessRunner::ScheduleIfNotRunning() { 89 if (!timer_.IsRunning()) 90 Schedule(); 91} 92 93void SyncProcessRunner::OnChangesUpdated( 94 int64 pending_changes) { 95 DCHECK_GE(pending_changes, 0); 96 int64 old_pending_changes = pending_changes_; 97 pending_changes_ = pending_changes; 98 if (old_pending_changes != pending_changes) { 99 if (pending_changes == 0) 100 sync_service()->OnSyncIdle(); 101 util::Log(logging::LOG_VERBOSE, FROM_HERE, 102 "[%s] pending_changes updated: %" PRId64, 103 name_.c_str(), pending_changes); 104 } 105 Schedule(); 106} 107 108SyncServiceState SyncProcessRunner::GetServiceState() { 109 return sync_service()->GetSyncServiceState(); 110} 111 112void SyncProcessRunner::Finished(SyncStatusCode status) { 113 DCHECK(running_); 114 running_ = false; 115 util::Log(logging::LOG_VERBOSE, FROM_HERE, 116 "[%s] * Finished (elapsed: %" PRId64 " sec)", 117 name_.c_str(), 118 (base::Time::Now() - last_scheduled_).InSeconds()); 119 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC || 120 status == SYNC_STATUS_FILE_BUSY) 121 ScheduleInternal(kSyncDelayMaxInMilliseconds); 122 else if (!WasSuccessfulSync(status) && 123 GetServiceState() == SYNC_SERVICE_RUNNING) 124 ScheduleInternal(kSyncDelayWithSyncError); 125 else 126 Schedule(); 127} 128 129void SyncProcessRunner::Run() { 130 if (running_) 131 return; 132 running_ = true; 133 last_scheduled_ = base::Time::Now(); 134 last_delay_ = current_delay_; 135 136 util::Log(logging::LOG_VERBOSE, FROM_HERE, 137 "[%s] * Started", name_.c_str()); 138 139 StartSync( 140 base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr())); 141} 142 143void SyncProcessRunner::ScheduleInternal(int64 delay) { 144 base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay); 145 146 if (timer_.IsRunning()) { 147 if (current_delay_ == delay) 148 return; 149 150 base::TimeDelta elapsed = base::Time::Now() - last_scheduled_; 151 if (elapsed < time_to_next) { 152 time_to_next = time_to_next - elapsed; 153 } else { 154 time_to_next = base::TimeDelta::FromMilliseconds( 155 kSyncDelayFastInMilliseconds); 156 } 157 timer_.Stop(); 158 } 159 160 if (current_delay_ != delay) { 161 util::Log(logging::LOG_VERBOSE, FROM_HERE, 162 "[%s] Scheduling task in %" PRId64 " secs", 163 name_.c_str(), time_to_next.InSeconds()); 164 } 165 current_delay_ = delay; 166 167 timer_.Start(FROM_HERE, time_to_next, this, &SyncProcessRunner::Run); 168} 169 170} // namespace sync_file_system 171