• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WasSuccessfulSync(SyncStatusCode status)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 
SyncProcessRunner(const std::string & name,SyncFileSystemService * sync_service)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 
~SyncProcessRunner()56 SyncProcessRunner::~SyncProcessRunner() {}
57 
Schedule()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 
ScheduleIfNotRunning()88 void SyncProcessRunner::ScheduleIfNotRunning() {
89   if (!timer_.IsRunning())
90     Schedule();
91 }
92 
OnChangesUpdated(int64 pending_changes)93 void 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 
GetServiceState()108 SyncServiceState SyncProcessRunner::GetServiceState() {
109   return sync_service()->GetSyncServiceState();
110 }
111 
Finished(SyncStatusCode status)112 void 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 
Run()129 void 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 
ScheduleInternal(int64 delay)143 void 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