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.h"
11 #include "base/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_updates_command.h"
19 #include "sync/engine/net/server_connection_manager.h"
20 #include "sync/engine/process_commit_response_command.h"
21 #include "sync/engine/process_updates_command.h"
22 #include "sync/engine/store_timestamps_command.h"
23 #include "sync/engine/syncer_types.h"
24 #include "sync/engine/throttled_data_type_tracker.h"
25 #include "sync/internal_api/public/base/unique_position.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 using sessions::StatusController
;
36 using sessions::SyncSession
;
37 using syncable::IS_UNAPPLIED_UPDATE
;
38 using syncable::SERVER_CTIME
;
39 using syncable::SERVER_IS_DEL
;
40 using syncable::SERVER_IS_DIR
;
41 using syncable::SERVER_MTIME
;
42 using syncable::SERVER_NON_UNIQUE_NAME
;
43 using syncable::SERVER_PARENT_ID
;
44 using syncable::SERVER_SPECIFICS
;
45 using syncable::SERVER_UNIQUE_POSITION
;
46 using syncable::SERVER_VERSION
;
48 #define ENUM_CASE(x) case x: return #x
49 const char* SyncerStepToString(const SyncerStep step
)
52 ENUM_CASE(SYNCER_BEGIN
);
53 ENUM_CASE(DOWNLOAD_UPDATES
);
54 ENUM_CASE(PROCESS_UPDATES
);
55 ENUM_CASE(STORE_TIMESTAMPS
);
56 ENUM_CASE(APPLY_UPDATES
);
58 ENUM_CASE(SYNCER_END
);
66 : early_exit_requested_(false) {
71 bool Syncer::ExitRequested() {
72 base::AutoLock
lock(early_exit_requested_lock_
);
73 return early_exit_requested_
;
76 void Syncer::RequestEarlyExit() {
77 base::AutoLock
lock(early_exit_requested_lock_
);
78 early_exit_requested_
= true;
81 bool Syncer::SyncShare(sessions::SyncSession
* session
,
82 SyncerStep first_step
,
83 SyncerStep last_step
) {
84 session
->mutable_status_controller()->UpdateStartTime();
85 SyncerStep current_step
= first_step
;
87 SyncerStep next_step
= current_step
;
88 while (!ExitRequested()) {
89 TRACE_EVENT1("sync", "SyncerStateMachine",
90 "state", SyncerStepToString(current_step
));
91 DVLOG(1) << "Syncer step:" << SyncerStepToString(current_step
);
93 switch (current_step
) {
95 session
->context()->throttled_data_type_tracker()->
96 PruneUnthrottledTypes(base::TimeTicks::Now());
97 session
->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN
);
99 next_step
= DOWNLOAD_UPDATES
;
101 case DOWNLOAD_UPDATES
: {
102 // TODO(akalin): We may want to propagate this switch up
104 #if defined(OS_ANDROID) || defined(OS_IOS)
105 const bool kCreateMobileBookmarksFolder
= true;
107 const bool kCreateMobileBookmarksFolder
= false;
109 DownloadUpdatesCommand
download_updates(kCreateMobileBookmarksFolder
);
110 session
->mutable_status_controller()->set_last_download_updates_result(
111 download_updates
.Execute(session
));
112 next_step
= PROCESS_UPDATES
;
115 case PROCESS_UPDATES
: {
116 ProcessUpdatesCommand process_updates
;
117 process_updates
.Execute(session
);
118 next_step
= STORE_TIMESTAMPS
;
121 case STORE_TIMESTAMPS
: {
122 StoreTimestampsCommand store_timestamps
;
123 store_timestamps
.Execute(session
);
124 session
->SendEventNotification(SyncEngineEvent::STATUS_CHANGED
);
125 // We download all of the updates before attempting to apply them.
126 if (!session
->status_controller().download_updates_succeeded()) {
127 // We may have downloaded some updates, but if the latest download
128 // attempt failed then we don't have all the updates. We'll leave
129 // it to a retry job to pick up where we left off.
130 last_step
= SYNCER_END
; // Necessary for CONFIGURATION mode.
131 next_step
= SYNCER_END
;
132 DVLOG(1) << "Aborting sync cycle due to download updates failure";
133 } else if (!session
->status_controller()
134 .ServerSaysNothingMoreToDownload()) {
135 next_step
= DOWNLOAD_UPDATES
;
137 next_step
= APPLY_UPDATES
;
141 case APPLY_UPDATES
: {
142 // These include encryption updates that should be applied early.
143 ApplyControlDataUpdates(session
);
145 ApplyUpdatesAndResolveConflictsCommand apply_updates
;
146 apply_updates
.Execute(session
);
148 session
->context()->set_hierarchy_conflict_detected(
149 session
->status_controller().num_hierarchy_conflicts() > 0);
151 session
->SendEventNotification(SyncEngineEvent::STATUS_CHANGED
);
152 if (last_step
== APPLY_UPDATES
) {
153 // We're in configuration mode, but we still need to run the
155 last_step
= SYNCER_END
;
156 next_step
= SYNCER_END
;
163 session
->mutable_status_controller()->set_commit_result(
164 BuildAndPostCommits(this, session
));
165 next_step
= SYNCER_END
;
169 session
->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_ENDED
);
170 next_step
= SYNCER_END
;
174 LOG(ERROR
) << "Unknown command: " << current_step
;
176 DVLOG(2) << "last step: " << SyncerStepToString(last_step
) << ", "
177 << "current step: " << SyncerStepToString(current_step
) << ", "
178 << "next step: " << SyncerStepToString(next_step
) << ", "
179 << "snapshot: " << session
->TakeSnapshot().ToString();
180 if (last_step
== current_step
)
182 current_step
= next_step
;
187 void CopyServerFields(syncable::Entry
* src
, syncable::MutableEntry
* dest
) {
188 dest
->Put(SERVER_NON_UNIQUE_NAME
, src
->Get(SERVER_NON_UNIQUE_NAME
));
189 dest
->Put(SERVER_PARENT_ID
, src
->Get(SERVER_PARENT_ID
));
190 dest
->Put(SERVER_MTIME
, src
->Get(SERVER_MTIME
));
191 dest
->Put(SERVER_CTIME
, src
->Get(SERVER_CTIME
));
192 dest
->Put(SERVER_VERSION
, src
->Get(SERVER_VERSION
));
193 dest
->Put(SERVER_IS_DIR
, src
->Get(SERVER_IS_DIR
));
194 dest
->Put(SERVER_IS_DEL
, src
->Get(SERVER_IS_DEL
));
195 dest
->Put(IS_UNAPPLIED_UPDATE
, src
->Get(IS_UNAPPLIED_UPDATE
));
196 dest
->Put(SERVER_SPECIFICS
, src
->Get(SERVER_SPECIFICS
));
197 dest
->Put(SERVER_UNIQUE_POSITION
, src
->Get(SERVER_UNIQUE_POSITION
));
200 } // namespace syncer