Home | History | Annotate | Download | only in sync_file_system
      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