| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "sync/engine/syncer.h" |
| |
| #include "base/debug/trace_event.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "sync/engine/apply_control_data_updates.h" |
| #include "sync/engine/apply_updates_and_resolve_conflicts_command.h" |
| #include "sync/engine/build_commit_command.h" |
| #include "sync/engine/commit.h" |
| #include "sync/engine/conflict_resolver.h" |
| #include "sync/engine/download.h" |
| #include "sync/engine/net/server_connection_manager.h" |
| #include "sync/engine/process_commit_response_command.h" |
| #include "sync/engine/syncer_types.h" |
| #include "sync/internal_api/public/base/cancelation_signal.h" |
| #include "sync/internal_api/public/base/unique_position.h" |
| #include "sync/internal_api/public/util/syncer_error.h" |
| #include "sync/sessions/nudge_tracker.h" |
| #include "sync/syncable/mutable_entry.h" |
| #include "sync/syncable/syncable-inl.h" |
| |
| using base::Time; |
| using base::TimeDelta; |
| using sync_pb::ClientCommand; |
| |
| namespace syncer { |
| |
| // TODO(akalin): We may want to propagate this switch up |
| // eventually. |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| static const bool kCreateMobileBookmarksFolder = true; |
| #else |
| static const bool kCreateMobileBookmarksFolder = false; |
| #endif |
| |
| using sessions::StatusController; |
| using sessions::SyncSession; |
| using sessions::NudgeTracker; |
| |
| Syncer::Syncer(syncer::CancelationSignal* cancelation_signal) |
| : cancelation_signal_(cancelation_signal) { |
| } |
| |
| Syncer::~Syncer() {} |
| |
| bool Syncer::ExitRequested() { |
| return cancelation_signal_->IsSignalled(); |
| } |
| |
| bool Syncer::NormalSyncShare(ModelTypeSet request_types, |
| const NudgeTracker& nudge_tracker, |
| SyncSession* session) { |
| HandleCycleBegin(session); |
| VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types); |
| if (nudge_tracker.IsGetUpdatesRequired() || |
| session->context()->ShouldFetchUpdatesBeforeCommit()) { |
| if (!DownloadAndApplyUpdates( |
| session, |
| base::Bind(&BuildNormalDownloadUpdates, |
| session, |
| kCreateMobileBookmarksFolder, |
| request_types, |
| base::ConstRef(nudge_tracker)))) { |
| return HandleCycleEnd(session, nudge_tracker.updates_source()); |
| } |
| } |
| |
| VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types); |
| SyncerError commit_result = BuildAndPostCommits(request_types, this, session); |
| session->mutable_status_controller()->set_commit_result(commit_result); |
| |
| return HandleCycleEnd(session, nudge_tracker.updates_source()); |
| } |
| |
| bool Syncer::ConfigureSyncShare( |
| ModelTypeSet request_types, |
| sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, |
| SyncSession* session) { |
| HandleCycleBegin(session); |
| VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types); |
| DownloadAndApplyUpdates( |
| session, |
| base::Bind(&BuildDownloadUpdatesForConfigure, |
| session, |
| kCreateMobileBookmarksFolder, |
| source, |
| request_types)); |
| return HandleCycleEnd(session, source); |
| } |
| |
| bool Syncer::PollSyncShare(ModelTypeSet request_types, |
| SyncSession* session) { |
| HandleCycleBegin(session); |
| VLOG(1) << "Polling types " << ModelTypeSetToString(request_types); |
| DownloadAndApplyUpdates( |
| session, |
| base::Bind(&BuildDownloadUpdatesForPoll, |
| session, |
| kCreateMobileBookmarksFolder, |
| request_types)); |
| return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC); |
| } |
| |
| void Syncer::ApplyUpdates(SyncSession* session) { |
| TRACE_EVENT0("sync", "ApplyUpdates"); |
| |
| ApplyControlDataUpdates(session); |
| |
| ApplyUpdatesAndResolveConflictsCommand apply_updates; |
| apply_updates.Execute(session); |
| |
| session->context()->set_hierarchy_conflict_detected( |
| session->status_controller().num_hierarchy_conflicts() > 0); |
| |
| session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED); |
| } |
| |
| bool Syncer::DownloadAndApplyUpdates( |
| SyncSession* session, |
| base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn) { |
| while (!session->status_controller().ServerSaysNothingMoreToDownload()) { |
| TRACE_EVENT0("sync", "DownloadUpdates"); |
| sync_pb::ClientToServerMessage msg; |
| build_fn.Run(&msg); |
| SyncerError download_result = ExecuteDownloadUpdates(session, &msg); |
| session->mutable_status_controller()->set_last_download_updates_result( |
| download_result); |
| if (download_result != SYNCER_OK) { |
| return false; |
| } |
| } |
| if (ExitRequested()) |
| return false; |
| ApplyUpdates(session); |
| if (ExitRequested()) |
| return false; |
| return true; |
| } |
| |
| void Syncer::HandleCycleBegin(SyncSession* session) { |
| session->mutable_status_controller()->UpdateStartTime(); |
| session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN); |
| } |
| |
| bool Syncer::HandleCycleEnd( |
| SyncSession* session, |
| sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) { |
| if (!ExitRequested()) { |
| session->SendSyncCycleEndEventNotification(source); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| } // namespace syncer |