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/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/get_updates_delegate.h"
18 #include "sync/engine/get_updates_processor.h"
19 #include "sync/engine/net/server_connection_manager.h"
20 #include "sync/engine/syncer_types.h"
21 #include "sync/internal_api/public/base/cancelation_signal.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/directory.h"
26 #include "sync/syncable/mutable_entry.h"
27 #include "sync/syncable/syncable-inl.h"
30 using base::TimeDelta
;
31 using sync_pb::ClientCommand
;
35 // TODO(akalin): We may want to propagate this switch up
37 #if defined(OS_ANDROID) || defined(OS_IOS)
38 static const bool kCreateMobileBookmarksFolder
= true;
40 static const bool kCreateMobileBookmarksFolder
= false;
43 using sessions::StatusController
;
44 using sessions::SyncSession
;
45 using sessions::NudgeTracker
;
47 Syncer::Syncer(syncer::CancelationSignal
* cancelation_signal
)
48 : cancelation_signal_(cancelation_signal
) {
53 bool Syncer::ExitRequested() {
54 return cancelation_signal_
->IsSignalled();
57 bool Syncer::NormalSyncShare(ModelTypeSet request_types
,
58 const NudgeTracker
& nudge_tracker
,
59 SyncSession
* session
) {
60 HandleCycleBegin(session
);
61 if (nudge_tracker
.IsGetUpdatesRequired() ||
62 session
->context()->ShouldFetchUpdatesBeforeCommit()) {
63 VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types
);
64 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
65 GetUpdatesProcessor
get_updates_processor(
66 session
->context()->model_type_registry()->update_handler_map(),
68 if (!DownloadAndApplyUpdates(
71 &get_updates_processor
,
72 kCreateMobileBookmarksFolder
)) {
73 return HandleCycleEnd(session
, nudge_tracker
.GetLegacySource());
77 VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types
);
78 CommitProcessor
commit_processor(
79 session
->context()->model_type_registry()->commit_contributor_map());
80 SyncerError commit_result
=
81 BuildAndPostCommits(request_types
, session
, &commit_processor
);
82 session
->mutable_status_controller()->set_commit_result(commit_result
);
84 return HandleCycleEnd(session
, nudge_tracker
.GetLegacySource());
87 bool Syncer::ConfigureSyncShare(
88 ModelTypeSet request_types
,
89 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source
,
90 SyncSession
* session
) {
91 VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types
);
92 HandleCycleBegin(session
);
93 ConfigureGetUpdatesDelegate
configure_delegate(source
);
94 GetUpdatesProcessor
get_updates_processor(
95 session
->context()->model_type_registry()->update_handler_map(),
97 DownloadAndApplyUpdates(
100 &get_updates_processor
,
101 kCreateMobileBookmarksFolder
);
102 return HandleCycleEnd(session
, source
);
105 bool Syncer::PollSyncShare(ModelTypeSet request_types
,
106 SyncSession
* session
) {
107 VLOG(1) << "Polling types " << ModelTypeSetToString(request_types
);
108 HandleCycleBegin(session
);
109 PollGetUpdatesDelegate poll_delegate
;
110 GetUpdatesProcessor
get_updates_processor(
111 session
->context()->model_type_registry()->update_handler_map(),
113 DownloadAndApplyUpdates(
116 &get_updates_processor
,
117 kCreateMobileBookmarksFolder
);
118 return HandleCycleEnd(session
, sync_pb::GetUpdatesCallerInfo::PERIODIC
);
121 bool Syncer::DownloadAndApplyUpdates(
122 ModelTypeSet request_types
,
123 SyncSession
* session
,
124 GetUpdatesProcessor
* get_updates_processor
,
125 bool create_mobile_bookmarks_folder
) {
126 SyncerError download_result
= UNSET
;
128 download_result
= get_updates_processor
->DownloadUpdates(
131 create_mobile_bookmarks_folder
);
132 } while (download_result
== SERVER_MORE_TO_DOWNLOAD
);
134 // Exit without applying if we're shutting down or an error was detected.
135 if (download_result
!= SYNCER_OK
)
141 TRACE_EVENT0("sync", "ApplyUpdates");
143 // Control type updates always get applied first.
144 ApplyControlDataUpdates(session
->context()->directory());
146 // Apply upates to the other types. May or may not involve cross-thread
147 // traffic, depending on the underlying update handlers and the GU type's
149 get_updates_processor
->ApplyUpdates(request_types
,
150 session
->mutable_status_controller());
152 session
->context()->set_hierarchy_conflict_detected(
153 session
->status_controller().num_hierarchy_conflicts() > 0);
154 session
->SendEventNotification(SyncCycleEvent::STATUS_CHANGED
);
162 SyncerError
Syncer::BuildAndPostCommits(ModelTypeSet requested_types
,
163 sessions::SyncSession
* session
,
164 CommitProcessor
* commit_processor
) {
165 // The ExitRequested() check is unnecessary, since we should start getting
166 // errors from the ServerConnectionManager if an exist has been requested.
167 // However, it doesn't hurt to check it anyway.
168 while (!ExitRequested()) {
169 scoped_ptr
<Commit
> commit(
172 session
->context()->GetEnabledTypes(),
173 session
->context()->max_commit_batch_size(),
174 session
->context()->account_name(),
175 session
->context()->directory()->cache_guid(),
177 session
->context()->extensions_activity()));
182 SyncerError error
= commit
->PostAndProcessResponse(
184 session
->mutable_status_controller(),
185 session
->context()->extensions_activity());
187 if (error
!= SYNCER_OK
) {
195 void Syncer::HandleCycleBegin(SyncSession
* session
) {
196 session
->mutable_status_controller()->UpdateStartTime();
197 session
->SendEventNotification(SyncCycleEvent::SYNC_CYCLE_BEGIN
);
200 bool Syncer::HandleCycleEnd(
201 SyncSession
* session
,
202 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source
) {
203 if (!ExitRequested()) {
204 session
->SendSyncCycleEndEventNotification(source
);
211 } // namespace syncer