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/commit.h"
     15 #include "sync/engine/commit_processor.h"
     16 #include "sync/engine/conflict_resolver.h"
     17 #include "sync/engine/get_updates_delegate.h"
     18 #include "sync/engine/get_updates_processor.h"
     19 #include "sync/engine/net/server_connection_manager.h"
     20 #include "sync/engine/syncer_types.h"
     21 #include "sync/internal_api/public/base/cancelation_signal.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/directory.h"
     26 #include "sync/syncable/mutable_entry.h"
     27 #include "sync/syncable/syncable-inl.h"
     28 
     29 using base::Time;
     30 using base::TimeDelta;
     31 using sync_pb::ClientCommand;
     32 
     33 namespace syncer {
     34 
     35 // TODO(akalin): We may want to propagate this switch up
     36 // eventually.
     37 #if defined(OS_ANDROID) || defined(OS_IOS)
     38 static const bool kCreateMobileBookmarksFolder = true;
     39 #else
     40 static const bool kCreateMobileBookmarksFolder = false;
     41 #endif
     42 
     43 using sessions::StatusController;
     44 using sessions::SyncSession;
     45 using sessions::NudgeTracker;
     46 
     47 Syncer::Syncer(syncer::CancelationSignal* cancelation_signal)
     48     : cancelation_signal_(cancelation_signal) {
     49 }
     50 
     51 Syncer::~Syncer() {}
     52 
     53 bool Syncer::ExitRequested() {
     54   return cancelation_signal_->IsSignalled();
     55 }
     56 
     57 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
     58                              const NudgeTracker& nudge_tracker,
     59                              SyncSession* session) {
     60   HandleCycleBegin(session);
     61   if (nudge_tracker.IsGetUpdatesRequired() ||
     62       session->context()->ShouldFetchUpdatesBeforeCommit()) {
     63     VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
     64     NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
     65     GetUpdatesProcessor get_updates_processor(
     66         session->context()->model_type_registry()->update_handler_map(),
     67         normal_delegate);
     68     if (!DownloadAndApplyUpdates(
     69             request_types,
     70             session,
     71             &get_updates_processor,
     72             kCreateMobileBookmarksFolder)) {
     73       return HandleCycleEnd(session, nudge_tracker.GetLegacySource());
     74     }
     75   }
     76 
     77   VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
     78   CommitProcessor commit_processor(
     79       session->context()->model_type_registry()->commit_contributor_map());
     80   SyncerError commit_result =
     81       BuildAndPostCommits(request_types, session, &commit_processor);
     82   session->mutable_status_controller()->set_commit_result(commit_result);
     83 
     84   return HandleCycleEnd(session, nudge_tracker.GetLegacySource());
     85 }
     86 
     87 bool Syncer::ConfigureSyncShare(
     88     ModelTypeSet request_types,
     89     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
     90     SyncSession* session) {
     91   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
     92   HandleCycleBegin(session);
     93   ConfigureGetUpdatesDelegate configure_delegate(source);
     94   GetUpdatesProcessor get_updates_processor(
     95       session->context()->model_type_registry()->update_handler_map(),
     96       configure_delegate);
     97   DownloadAndApplyUpdates(
     98       request_types,
     99       session,
    100       &get_updates_processor,
    101       kCreateMobileBookmarksFolder);
    102   return HandleCycleEnd(session, source);
    103 }
    104 
    105 bool Syncer::PollSyncShare(ModelTypeSet request_types,
    106                            SyncSession* session) {
    107   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
    108   HandleCycleBegin(session);
    109   PollGetUpdatesDelegate poll_delegate;
    110   GetUpdatesProcessor get_updates_processor(
    111       session->context()->model_type_registry()->update_handler_map(),
    112       poll_delegate);
    113   DownloadAndApplyUpdates(
    114       request_types,
    115       session,
    116       &get_updates_processor,
    117       kCreateMobileBookmarksFolder);
    118   return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC);
    119 }
    120 
    121 bool Syncer::DownloadAndApplyUpdates(
    122     ModelTypeSet request_types,
    123     SyncSession* session,
    124     GetUpdatesProcessor* get_updates_processor,
    125     bool create_mobile_bookmarks_folder) {
    126   SyncerError download_result = UNSET;
    127   do {
    128     download_result = get_updates_processor->DownloadUpdates(
    129         request_types,
    130         session,
    131         create_mobile_bookmarks_folder);
    132   } while (download_result == SERVER_MORE_TO_DOWNLOAD);
    133 
    134   // Exit without applying if we're shutting down or an error was detected.
    135   if (download_result != SYNCER_OK)
    136     return false;
    137   if (ExitRequested())
    138     return false;
    139 
    140   {
    141     TRACE_EVENT0("sync", "ApplyUpdates");
    142 
    143     // Control type updates always get applied first.
    144     ApplyControlDataUpdates(session->context()->directory());
    145 
    146     // Apply upates to the other types.  May or may not involve cross-thread
    147     // traffic, depending on the underlying update handlers and the GU type's
    148     // delegate.
    149     get_updates_processor->ApplyUpdates(request_types,
    150                                         session->mutable_status_controller());
    151 
    152     session->context()->set_hierarchy_conflict_detected(
    153         session->status_controller().num_hierarchy_conflicts() > 0);
    154     session->SendEventNotification(SyncCycleEvent::STATUS_CHANGED);
    155   }
    156 
    157   if (ExitRequested())
    158     return false;
    159   return true;
    160 }
    161 
    162 SyncerError Syncer::BuildAndPostCommits(ModelTypeSet requested_types,
    163                                         sessions::SyncSession* session,
    164                                         CommitProcessor* commit_processor) {
    165   // The ExitRequested() check is unnecessary, since we should start getting
    166   // errors from the ServerConnectionManager if an exist has been requested.
    167   // However, it doesn't hurt to check it anyway.
    168   while (!ExitRequested()) {
    169     scoped_ptr<Commit> commit(
    170         Commit::Init(
    171             requested_types,
    172             session->context()->GetEnabledTypes(),
    173             session->context()->max_commit_batch_size(),
    174             session->context()->account_name(),
    175             session->context()->directory()->cache_guid(),
    176             commit_processor,
    177             session->context()->extensions_activity()));
    178     if (!commit) {
    179       break;
    180     }
    181 
    182     SyncerError error = commit->PostAndProcessResponse(
    183         session,
    184         session->mutable_status_controller(),
    185         session->context()->extensions_activity());
    186     commit->CleanUp();
    187     if (error != SYNCER_OK) {
    188       return error;
    189     }
    190   }
    191 
    192   return SYNCER_OK;
    193 }
    194 
    195 void Syncer::HandleCycleBegin(SyncSession* session) {
    196   session->mutable_status_controller()->UpdateStartTime();
    197   session->SendEventNotification(SyncCycleEvent::SYNC_CYCLE_BEGIN);
    198 }
    199 
    200 bool Syncer::HandleCycleEnd(
    201     SyncSession* session,
    202     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
    203   if (!ExitRequested()) {
    204     session->SendSyncCycleEndEventNotification(source);
    205     return true;
    206   } else {
    207     return false;
    208   }
    209 }
    210 
    211 }  // namespace syncer
    212