Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sync / engine / syncer.cc
blob5eccd80161cbef286d02a5e7dd10cbb1a512eb5c
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.
5 #include "sync/engine/syncer.h"
7 #include "base/auto_reset.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 "base/trace_event/trace_event.h"
13 #include "build/build_config.h"
14 #include "sync/engine/apply_control_data_updates.h"
15 #include "sync/engine/clear_server_data.h"
16 #include "sync/engine/commit.h"
17 #include "sync/engine/commit_processor.h"
18 #include "sync/engine/conflict_resolver.h"
19 #include "sync/engine/get_updates_delegate.h"
20 #include "sync/engine/get_updates_processor.h"
21 #include "sync/engine/net/server_connection_manager.h"
22 #include "sync/engine/syncer_types.h"
23 #include "sync/internal_api/public/base/cancelation_signal.h"
24 #include "sync/internal_api/public/base/unique_position.h"
25 #include "sync/internal_api/public/util/syncer_error.h"
26 #include "sync/sessions/nudge_tracker.h"
27 #include "sync/syncable/directory.h"
28 #include "sync/syncable/mutable_entry.h"
29 #include "sync/syncable/syncable-inl.h"
31 using base::Time;
32 using base::TimeDelta;
33 using sync_pb::ClientCommand;
35 namespace syncer {
37 // TODO(akalin): We may want to propagate this switch up
38 // eventually.
39 #if defined(OS_ANDROID) || defined(OS_IOS)
40 static const bool kCreateMobileBookmarksFolder = true;
41 #else
42 static const bool kCreateMobileBookmarksFolder = false;
43 #endif
45 using sessions::StatusController;
46 using sessions::SyncSession;
47 using sessions::NudgeTracker;
49 Syncer::Syncer(syncer::CancelationSignal* cancelation_signal)
50 : cancelation_signal_(cancelation_signal),
51 is_syncing_(false) {
54 Syncer::~Syncer() {}
56 bool Syncer::ExitRequested() {
57 return cancelation_signal_->IsSignalled();
60 bool Syncer::IsSyncing() const {
61 return is_syncing_;
64 bool Syncer::NormalSyncShare(ModelTypeSet request_types,
65 NudgeTracker* nudge_tracker,
66 SyncSession* session) {
67 base::AutoReset<bool> is_syncing(&is_syncing_, true);
68 HandleCycleBegin(session);
69 if (nudge_tracker->IsGetUpdatesRequired() ||
70 session->context()->ShouldFetchUpdatesBeforeCommit()) {
71 VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
72 NormalGetUpdatesDelegate normal_delegate(*nudge_tracker);
73 GetUpdatesProcessor get_updates_processor(
74 session->context()->model_type_registry()->update_handler_map(),
75 normal_delegate);
76 if (!DownloadAndApplyUpdates(
77 &request_types,
78 session,
79 &get_updates_processor,
80 kCreateMobileBookmarksFolder)) {
81 return HandleCycleEnd(session, nudge_tracker->GetLegacySource());
85 VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
86 CommitProcessor commit_processor(
87 session->context()->model_type_registry()->commit_contributor_map());
88 SyncerError commit_result = BuildAndPostCommits(request_types, nudge_tracker,
89 session, &commit_processor);
90 session->mutable_status_controller()->set_commit_result(commit_result);
92 return HandleCycleEnd(session, nudge_tracker->GetLegacySource());
95 bool Syncer::ConfigureSyncShare(
96 ModelTypeSet request_types,
97 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
98 SyncSession* session) {
99 base::AutoReset<bool> is_syncing(&is_syncing_, true);
100 VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
101 HandleCycleBegin(session);
102 ConfigureGetUpdatesDelegate configure_delegate(source);
103 GetUpdatesProcessor get_updates_processor(
104 session->context()->model_type_registry()->update_handler_map(),
105 configure_delegate);
106 DownloadAndApplyUpdates(
107 &request_types,
108 session,
109 &get_updates_processor,
110 kCreateMobileBookmarksFolder);
111 return HandleCycleEnd(session, source);
114 bool Syncer::PollSyncShare(ModelTypeSet request_types,
115 SyncSession* session) {
116 base::AutoReset<bool> is_syncing(&is_syncing_, true);
117 VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
118 HandleCycleBegin(session);
119 PollGetUpdatesDelegate poll_delegate;
120 GetUpdatesProcessor get_updates_processor(
121 session->context()->model_type_registry()->update_handler_map(),
122 poll_delegate);
123 DownloadAndApplyUpdates(
124 &request_types,
125 session,
126 &get_updates_processor,
127 kCreateMobileBookmarksFolder);
128 return HandleCycleEnd(session, sync_pb::GetUpdatesCallerInfo::PERIODIC);
131 bool Syncer::DownloadAndApplyUpdates(
132 ModelTypeSet* request_types,
133 SyncSession* session,
134 GetUpdatesProcessor* get_updates_processor,
135 bool create_mobile_bookmarks_folder) {
136 SyncerError download_result = UNSET;
137 do {
138 download_result = get_updates_processor->DownloadUpdates(
139 request_types,
140 session,
141 create_mobile_bookmarks_folder);
142 } while (download_result == SERVER_MORE_TO_DOWNLOAD);
144 // Exit without applying if we're shutting down or an error was detected.
145 if (download_result != SYNCER_OK)
146 return false;
147 if (ExitRequested())
148 return false;
151 TRACE_EVENT0("sync", "ApplyUpdates");
153 // Control type updates always get applied first.
154 ApplyControlDataUpdates(session->context()->directory());
156 // Apply upates to the other types. May or may not involve cross-thread
157 // traffic, depending on the underlying update handlers and the GU type's
158 // delegate.
159 get_updates_processor->ApplyUpdates(*request_types,
160 session->mutable_status_controller());
162 session->context()->set_hierarchy_conflict_detected(
163 session->status_controller().num_hierarchy_conflicts() > 0);
164 session->SendEventNotification(SyncCycleEvent::STATUS_CHANGED);
167 if (ExitRequested())
168 return false;
169 return true;
172 SyncerError Syncer::BuildAndPostCommits(ModelTypeSet requested_types,
173 sessions::NudgeTracker* nudge_tracker,
174 sessions::SyncSession* session,
175 CommitProcessor* commit_processor) {
176 // The ExitRequested() check is unnecessary, since we should start getting
177 // errors from the ServerConnectionManager if an exist has been requested.
178 // However, it doesn't hurt to check it anyway.
179 while (!ExitRequested()) {
180 scoped_ptr<Commit> commit(
181 Commit::Init(
182 requested_types,
183 session->context()->GetEnabledTypes(),
184 session->context()->max_commit_batch_size(),
185 session->context()->account_name(),
186 session->context()->directory()->cache_guid(),
187 commit_processor,
188 session->context()->extensions_activity()));
189 if (!commit) {
190 break;
193 SyncerError error = commit->PostAndProcessResponse(
194 nudge_tracker, session, session->mutable_status_controller(),
195 session->context()->extensions_activity());
196 commit->CleanUp();
197 if (error != SYNCER_OK) {
198 return error;
202 return SYNCER_OK;
205 void Syncer::HandleCycleBegin(SyncSession* session) {
206 session->mutable_status_controller()->UpdateStartTime();
207 session->SendEventNotification(SyncCycleEvent::SYNC_CYCLE_BEGIN);
210 bool Syncer::HandleCycleEnd(
211 SyncSession* session,
212 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
213 if (!ExitRequested()) {
214 session->SendSyncCycleEndEventNotification(source);
216 bool success = !sessions::HasSyncerError(
217 session->status_controller().model_neutral_state());
218 if (success && source == sync_pb::GetUpdatesCallerInfo::PERIODIC)
219 session->mutable_status_controller()->UpdatePollTime();
220 return success;
221 } else {
222 return false;
226 bool Syncer::PostClearServerData(SyncSession* session) {
227 DCHECK(session);
228 ClearServerData clear_server_data(session->context()->account_name());
229 const SyncerError post_result = clear_server_data.SendRequest(session);
230 return post_result == SYNCER_OK;
233 } // namespace syncer