Home | History | Annotate | Download | only in engine
      1 // Copyright (c) 2012 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 "sync/engine/syncer.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/location.h"
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/time/time.h"
     12 #include "build/build_config.h"
     13 #include "sync/engine/apply_control_data_updates.h"
     14 #include "sync/engine/apply_updates_and_resolve_conflicts_command.h"
     15 #include "sync/engine/build_commit_command.h"
     16 #include "sync/engine/commit.h"
     17 #include "sync/engine/conflict_resolver.h"
     18 #include "sync/engine/download.h"
     19 #include "sync/engine/net/server_connection_manager.h"
     20 #include "sync/engine/process_commit_response_command.h"
     21 #include "sync/engine/syncer_types.h"
     22 #include "sync/internal_api/public/base/unique_position.h"
     23 #include "sync/internal_api/public/util/syncer_error.h"
     24 #include "sync/sessions/nudge_tracker.h"
     25 #include "sync/syncable/mutable_entry.h"
     26 #include "sync/syncable/syncable-inl.h"
     27 
     28 using base::Time;
     29 using base::TimeDelta;
     30 using sync_pb::ClientCommand;
     31 
     32 namespace syncer {
     33 
     34 // TODO(akalin): We may want to propagate this switch up
     35 // eventually.
     36 #if defined(OS_ANDROID) || defined(OS_IOS)
     37 static const bool kCreateMobileBookmarksFolder = true;
     38 #else
     39 static const bool kCreateMobileBookmarksFolder = false;
     40 #endif
     41 
     42 using sessions::StatusController;
     43 using sessions::SyncSession;
     44 using sessions::NudgeTracker;
     45 
     46 Syncer::Syncer()
     47     : early_exit_requested_(false) {
     48 }
     49 
     50 Syncer::~Syncer() {}
     51 
     52 bool Syncer::ExitRequested() {
     53   base::AutoLock lock(early_exit_requested_lock_);
     54   return early_exit_requested_;
     55 }
     56 
     57 void Syncer::RequestEarlyExit() {
     58   base::AutoLock lock(early_exit_requested_lock_);
     59   early_exit_requested_ = true;
     60 }
     61 
     62 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
     63                              const NudgeTracker& nudge_tracker,
     64                              SyncSession* session) {
     65   HandleCycleBegin(session);
     66   VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
     67   if (nudge_tracker.IsGetUpdatesRequired() ||
     68       session->context()->ShouldFetchUpdatesBeforeCommit()) {
     69     if (!DownloadAndApplyUpdates(
     70             session,
     71             base::Bind(&NormalDownloadUpdates,
     72                        session,
     73                        kCreateMobileBookmarksFolder,
     74                        request_types,
     75                        base::ConstRef(nudge_tracker)))) {
     76     return HandleCycleEnd(session, nudge_tracker.updates_source());
     77     }
     78   }
     79 
     80   VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
     81   SyncerError commit_result = BuildAndPostCommits(request_types, this, session);
     82   session->mutable_status_controller()->set_commit_result(commit_result);
     83 
     84   return HandleCycleEnd(session, nudge_tracker.updates_source());
     85 }
     86 
     87 bool Syncer::ConfigureSyncShare(
     88     ModelTypeSet request_types,
     89     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
     90     SyncSession* session) {
     91   HandleCycleBegin(session);
     92   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
     93   DownloadAndApplyUpdates(
     94       session,
     95       base::Bind(&DownloadUpdatesForConfigure,
     96                  session,
     97                  kCreateMobileBookmarksFolder,
     98                  source,
     99                  request_types));
    100   return HandleCycleEnd(session, source);
    101 }
    102 
    103 bool Syncer::PollSyncShare(ModelTypeSet request_types,
    104                            SyncSession* session) {
    105   HandleCycleBegin(session);
    106   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
    107   DownloadAndApplyUpdates(
    108       session,
    109       base::Bind(&DownloadUpdatesForPoll,
    110                  session,
    111                  kCreateMobileBookmarksFolder,
    112                  request_types));
    113   return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC);
    114 }
    115 
    116 void Syncer::ApplyUpdates(SyncSession* session) {
    117   TRACE_EVENT0("sync", "ApplyUpdates");
    118 
    119   ApplyControlDataUpdates(session);
    120 
    121   ApplyUpdatesAndResolveConflictsCommand apply_updates;
    122   apply_updates.Execute(session);
    123 
    124   session->context()->set_hierarchy_conflict_detected(
    125       session->status_controller().num_hierarchy_conflicts() > 0);
    126 
    127   session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED);
    128 }
    129 
    130 bool Syncer::DownloadAndApplyUpdates(
    131     SyncSession* session,
    132     base::Callback<SyncerError(void)> download_fn) {
    133   while (!session->status_controller().ServerSaysNothingMoreToDownload()) {
    134     SyncerError download_result = download_fn.Run();
    135     session->mutable_status_controller()->set_last_download_updates_result(
    136         download_result);
    137     if (download_result != SYNCER_OK) {
    138       return false;
    139     }
    140   }
    141   if (ExitRequested())
    142     return false;
    143   ApplyUpdates(session);
    144   if (ExitRequested())
    145     return false;
    146   return true;
    147 }
    148 
    149 void Syncer::HandleCycleBegin(SyncSession* session) {
    150   session->mutable_status_controller()->UpdateStartTime();
    151   session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN);
    152 }
    153 
    154 bool Syncer::HandleCycleEnd(
    155     SyncSession* session,
    156     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
    157   if (!ExitRequested()) {
    158     session->SendSyncCycleEndEventNotification(source);
    159     return true;
    160   } else {
    161     return false;
    162   }
    163 }
    164 
    165 }  // namespace syncer
    166