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