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 11 namespace sync_file_system { 12 13 namespace { 14 15 // Default delay when more changes are available. 16 const int64 kSyncDelayInMilliseconds = 1 * base::Time::kMillisecondsPerSecond; 17 18 // Default delay when the previous change has had an error (but remote service 19 // is running). 20 const int64 kSyncDelayWithSyncError = 3 * base::Time::kMillisecondsPerSecond; 21 22 // Default delay when there're more than 10 pending changes. 23 const int64 kSyncDelayFastInMilliseconds = 100; 24 const int kPendingChangeThresholdForFastSync = 10; 25 26 // Default delay when remote service is temporarily unavailable. 27 const int64 kSyncDelaySlowInMilliseconds = 28 30 * base::Time::kMillisecondsPerSecond; // Start with 30 sec + exp backoff 29 30 // Default delay when there're no changes. 31 const int64 kSyncDelayMaxInMilliseconds = 32 30 * 60 * base::Time::kMillisecondsPerSecond; // 30 min 33 34 bool 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 45 SyncProcessRunner::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 56 SyncProcessRunner::~SyncProcessRunner() {} 57 58 void 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 88 void SyncProcessRunner::ScheduleIfNotRunning() { 89 if (!timer_.IsRunning()) 90 Schedule(); 91 } 92 93 void SyncProcessRunner::OnChangesUpdated( 94 int64 pending_changes) { 95 DCHECK_GE(pending_changes, 0); 96 if (pending_changes_ != pending_changes) { 97 util::Log(logging::LOG_VERBOSE, FROM_HERE, 98 "[%s] pending_changes updated: %" PRId64, 99 name_.c_str(), pending_changes); 100 } 101 pending_changes_ = pending_changes; 102 Schedule(); 103 } 104 105 SyncServiceState SyncProcessRunner::GetServiceState() { 106 return sync_service()->GetSyncServiceState(); 107 } 108 109 void SyncProcessRunner::Finished(SyncStatusCode status) { 110 DCHECK(running_); 111 running_ = false; 112 util::Log(logging::LOG_VERBOSE, FROM_HERE, 113 "[%s] * Finished (elapsed: %" PRId64 " sec)", 114 name_.c_str(), 115 (base::Time::Now() - last_scheduled_).InSeconds()); 116 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC || 117 status == SYNC_STATUS_FILE_BUSY) 118 ScheduleInternal(kSyncDelayMaxInMilliseconds); 119 else if (!WasSuccessfulSync(status) && 120 GetServiceState() == SYNC_SERVICE_RUNNING) 121 ScheduleInternal(kSyncDelayWithSyncError); 122 else 123 Schedule(); 124 } 125 126 void SyncProcessRunner::Run() { 127 if (running_) 128 return; 129 running_ = true; 130 last_scheduled_ = base::Time::Now(); 131 last_delay_ = current_delay_; 132 133 util::Log(logging::LOG_VERBOSE, FROM_HERE, 134 "[%s] * Started", name_.c_str()); 135 136 StartSync( 137 base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr())); 138 } 139 140 void SyncProcessRunner::ScheduleInternal(int64 delay) { 141 base::TimeDelta time_to_next = base::TimeDelta::FromMilliseconds(delay); 142 143 if (timer_.IsRunning()) { 144 if (current_delay_ == delay) 145 return; 146 147 base::TimeDelta elapsed = base::Time::Now() - last_scheduled_; 148 if (elapsed < time_to_next) { 149 time_to_next = time_to_next - elapsed; 150 } else { 151 time_to_next = base::TimeDelta::FromMilliseconds( 152 kSyncDelayFastInMilliseconds); 153 } 154 timer_.Stop(); 155 } 156 157 if (current_delay_ != delay) { 158 util::Log(logging::LOG_VERBOSE, FROM_HERE, 159 "[%s] Scheduling task in %" PRId64 " secs", 160 name_.c_str(), time_to_next.InSeconds()); 161 } 162 current_delay_ = delay; 163 164 timer_.Start(FROM_HERE, time_to_next, this, &SyncProcessRunner::Run); 165 } 166 167 } // namespace sync_file_system 168