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