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