OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/engine/syncer.h" | 5 #include "sync/engine/syncer.h" |
6 | 6 |
7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/time.h" | 11 #include "base/time.h" |
12 #include "build/build_config.h" | 12 #include "build/build_config.h" |
13 #include "sync/engine/apply_control_data_updates.h" | 13 #include "sync/engine/apply_control_data_updates.h" |
14 #include "sync/engine/apply_updates_and_resolve_conflicts_command.h" | 14 #include "sync/engine/apply_updates_and_resolve_conflicts_command.h" |
15 #include "sync/engine/build_commit_command.h" | 15 #include "sync/engine/build_commit_command.h" |
16 #include "sync/engine/commit.h" | 16 #include "sync/engine/commit.h" |
17 #include "sync/engine/conflict_resolver.h" | 17 #include "sync/engine/conflict_resolver.h" |
18 #include "sync/engine/download_updates_command.h" | 18 #include "sync/engine/download.h" |
19 #include "sync/engine/net/server_connection_manager.h" | 19 #include "sync/engine/net/server_connection_manager.h" |
20 #include "sync/engine/process_commit_response_command.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" | 21 #include "sync/engine/syncer_types.h" |
24 #include "sync/internal_api/public/base/unique_position.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/mutable_entry.h" | 25 #include "sync/syncable/mutable_entry.h" |
26 #include "sync/syncable/syncable-inl.h" | 26 #include "sync/syncable/syncable-inl.h" |
27 | 27 |
28 using base::Time; | 28 using base::Time; |
29 using base::TimeDelta; | 29 using base::TimeDelta; |
30 using sync_pb::ClientCommand; | 30 using sync_pb::ClientCommand; |
31 | 31 |
32 namespace syncer { | 32 namespace syncer { |
33 | 33 |
| 34 // TODO(akalin): We may want to propagate this switch up |
| 35 // eventually. |
| 36 #if defined(OS_ANDROID) || defined(OS_IOS) |
| 37 static const bool kCreateMobileBookmarksFolder = true; |
| 38 #else |
| 39 static const bool kCreateMobileBookmarksFolder = false; |
| 40 #endif |
| 41 |
34 using sessions::StatusController; | 42 using sessions::StatusController; |
35 using sessions::SyncSession; | 43 using sessions::SyncSession; |
36 using syncable::IS_UNAPPLIED_UPDATE; | 44 using sessions::NudgeTracker; |
37 using syncable::SERVER_CTIME; | |
38 using syncable::SERVER_IS_DEL; | |
39 using syncable::SERVER_IS_DIR; | |
40 using syncable::SERVER_MTIME; | |
41 using syncable::SERVER_NON_UNIQUE_NAME; | |
42 using syncable::SERVER_PARENT_ID; | |
43 using syncable::SERVER_SPECIFICS; | |
44 using syncable::SERVER_UNIQUE_POSITION; | |
45 using syncable::SERVER_VERSION; | |
46 | |
47 #define ENUM_CASE(x) case x: return #x | |
48 const char* SyncerStepToString(const SyncerStep step) | |
49 { | |
50 switch (step) { | |
51 ENUM_CASE(SYNCER_BEGIN); | |
52 ENUM_CASE(DOWNLOAD_UPDATES); | |
53 ENUM_CASE(PROCESS_UPDATES); | |
54 ENUM_CASE(STORE_TIMESTAMPS); | |
55 ENUM_CASE(APPLY_UPDATES); | |
56 ENUM_CASE(COMMIT); | |
57 ENUM_CASE(SYNCER_END); | |
58 } | |
59 NOTREACHED(); | |
60 return ""; | |
61 } | |
62 #undef ENUM_CASE | |
63 | 45 |
64 Syncer::Syncer() | 46 Syncer::Syncer() |
65 : early_exit_requested_(false) { | 47 : early_exit_requested_(false) { |
66 } | 48 } |
67 | 49 |
68 Syncer::~Syncer() {} | 50 Syncer::~Syncer() {} |
69 | 51 |
70 bool Syncer::ExitRequested() { | 52 bool Syncer::ExitRequested() { |
71 base::AutoLock lock(early_exit_requested_lock_); | 53 base::AutoLock lock(early_exit_requested_lock_); |
72 return early_exit_requested_; | 54 return early_exit_requested_; |
73 } | 55 } |
74 | 56 |
75 void Syncer::RequestEarlyExit() { | 57 void Syncer::RequestEarlyExit() { |
76 base::AutoLock lock(early_exit_requested_lock_); | 58 base::AutoLock lock(early_exit_requested_lock_); |
77 early_exit_requested_ = true; | 59 early_exit_requested_ = true; |
78 } | 60 } |
79 | 61 |
80 bool Syncer::SyncShare(sessions::SyncSession* session, | 62 bool Syncer::NormalSyncShare(SyncSession* session, |
81 SyncerStep first_step, | 63 ModelTypeSet request_types, |
82 SyncerStep last_step) { | 64 const NudgeTracker& nudge_tracker) { |
83 session->mutable_status_controller()->UpdateStartTime(); | 65 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN); |
84 SyncerStep current_step = first_step; | |
85 | 66 |
86 SyncerStep next_step = current_step; | 67 VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types); |
87 while (!ExitRequested()) { | 68 while (!session->status_controller().ServerSaysNothingMoreToDownload()) { |
88 TRACE_EVENT1("sync", "SyncerStateMachine", | 69 SyncerError download_result = syncer::NormalDownloadUpdates( |
89 "state", SyncerStepToString(current_step)); | 70 session, |
90 DVLOG(1) << "Syncer step:" << SyncerStepToString(current_step); | 71 kCreateMobileBookmarksFolder, |
| 72 request_types, |
| 73 nudge_tracker); |
91 | 74 |
92 switch (current_step) { | 75 session->mutable_status_controller()->set_last_download_updates_result( |
93 case SYNCER_BEGIN: | 76 download_result); |
94 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN); | 77 if (download_result != SYNCER_OK) |
| 78 return true; |
| 79 } |
| 80 ApplyUpdates(session); |
95 | 81 |
96 next_step = DOWNLOAD_UPDATES; | 82 if (ExitRequested()) |
97 break; | 83 return false; |
98 case DOWNLOAD_UPDATES: { | |
99 // TODO(akalin): We may want to propagate this switch up | |
100 // eventually. | |
101 #if defined(OS_ANDROID) || defined(OS_IOS) | |
102 const bool kCreateMobileBookmarksFolder = true; | |
103 #else | |
104 const bool kCreateMobileBookmarksFolder = false; | |
105 #endif | |
106 DownloadUpdatesCommand download_updates(kCreateMobileBookmarksFolder); | |
107 session->mutable_status_controller()->set_last_download_updates_result( | |
108 download_updates.Execute(session)); | |
109 next_step = PROCESS_UPDATES; | |
110 break; | |
111 } | |
112 case PROCESS_UPDATES: { | |
113 ProcessUpdatesCommand process_updates; | |
114 process_updates.Execute(session); | |
115 next_step = STORE_TIMESTAMPS; | |
116 break; | |
117 } | |
118 case STORE_TIMESTAMPS: { | |
119 StoreTimestampsCommand store_timestamps; | |
120 store_timestamps.Execute(session); | |
121 session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED); | |
122 // We download all of the updates before attempting to apply them. | |
123 if (!session->status_controller().download_updates_succeeded()) { | |
124 // We may have downloaded some updates, but if the latest download | |
125 // attempt failed then we don't have all the updates. We'll leave | |
126 // it to a retry job to pick up where we left off. | |
127 last_step = SYNCER_END; // Necessary for CONFIGURATION mode. | |
128 next_step = SYNCER_END; | |
129 DVLOG(1) << "Aborting sync cycle due to download updates failure"; | |
130 } else if (!session->status_controller() | |
131 .ServerSaysNothingMoreToDownload()) { | |
132 next_step = DOWNLOAD_UPDATES; | |
133 } else { | |
134 next_step = APPLY_UPDATES; | |
135 } | |
136 break; | |
137 } | |
138 case APPLY_UPDATES: { | |
139 // These include encryption updates that should be applied early. | |
140 ApplyControlDataUpdates(session); | |
141 | 84 |
142 ApplyUpdatesAndResolveConflictsCommand apply_updates; | 85 VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types); |
143 apply_updates.Execute(session); | 86 SyncerError commit_result = BuildAndPostCommits(request_types, this, session); |
| 87 session->mutable_status_controller()->set_commit_result(commit_result); |
144 | 88 |
145 session->context()->set_hierarchy_conflict_detected( | 89 if (ExitRequested()) { |
146 session->status_controller().num_hierarchy_conflicts() > 0); | 90 return false; |
147 | 91 } else { |
148 session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED); | 92 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_ENDED); |
149 if (last_step == APPLY_UPDATES) { | 93 return true; |
150 // We're in configuration mode, but we still need to run the | 94 } |
151 // SYNCER_END step. | |
152 last_step = SYNCER_END; | |
153 next_step = SYNCER_END; | |
154 } else { | |
155 next_step = COMMIT; | |
156 } | |
157 break; | |
158 } | |
159 case COMMIT: { | |
160 session->mutable_status_controller()->set_commit_result( | |
161 BuildAndPostCommits(this, session)); | |
162 next_step = SYNCER_END; | |
163 break; | |
164 } | |
165 case SYNCER_END: { | |
166 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_ENDED); | |
167 next_step = SYNCER_END; | |
168 break; | |
169 } | |
170 default: | |
171 LOG(ERROR) << "Unknown command: " << current_step; | |
172 } // switch | |
173 DVLOG(2) << "last step: " << SyncerStepToString(last_step) << ", " | |
174 << "current step: " << SyncerStepToString(current_step) << ", " | |
175 << "next step: " << SyncerStepToString(next_step) << ", " | |
176 << "snapshot: " << session->TakeSnapshot().ToString(); | |
177 if (last_step == current_step) | |
178 return true; | |
179 current_step = next_step; | |
180 } // while | |
181 return false; | |
182 } | 95 } |
183 | 96 |
184 void CopyServerFields(syncable::Entry* src, syncable::MutableEntry* dest) { | 97 bool Syncer::ConfigureSyncShare(SyncSession* session, |
185 dest->Put(SERVER_NON_UNIQUE_NAME, src->Get(SERVER_NON_UNIQUE_NAME)); | 98 ModelTypeSet request_types) { |
186 dest->Put(SERVER_PARENT_ID, src->Get(SERVER_PARENT_ID)); | 99 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN); |
187 dest->Put(SERVER_MTIME, src->Get(SERVER_MTIME)); | 100 |
188 dest->Put(SERVER_CTIME, src->Get(SERVER_CTIME)); | 101 while (!session->status_controller().ServerSaysNothingMoreToDownload()) { |
189 dest->Put(SERVER_VERSION, src->Get(SERVER_VERSION)); | 102 SyncerError download_result = ConfigureDownloadUpdates( |
190 dest->Put(SERVER_IS_DIR, src->Get(SERVER_IS_DIR)); | 103 session, |
191 dest->Put(SERVER_IS_DEL, src->Get(SERVER_IS_DEL)); | 104 kCreateMobileBookmarksFolder, |
192 dest->Put(IS_UNAPPLIED_UPDATE, src->Get(IS_UNAPPLIED_UPDATE)); | 105 session->source(), |
193 dest->Put(SERVER_SPECIFICS, src->Get(SERVER_SPECIFICS)); | 106 request_types); |
194 dest->Put(SERVER_UNIQUE_POSITION, src->Get(SERVER_UNIQUE_POSITION)); | 107 session->mutable_status_controller()->set_last_download_updates_result( |
| 108 download_result); |
| 109 if (download_result != SYNCER_OK) |
| 110 return true; |
| 111 } |
| 112 ApplyUpdates(session); |
| 113 |
| 114 if (ExitRequested()) { |
| 115 return false; |
| 116 } else { |
| 117 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_ENDED); |
| 118 return true; |
| 119 } |
| 120 } |
| 121 |
| 122 bool Syncer::PollSyncShare(SyncSession* session, |
| 123 ModelTypeSet request_types) { |
| 124 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_BEGIN); |
| 125 |
| 126 while (!session->status_controller().ServerSaysNothingMoreToDownload()) { |
| 127 SyncerError download_result = PollDownloadUpdates( |
| 128 session, |
| 129 kCreateMobileBookmarksFolder, |
| 130 request_types); |
| 131 session->mutable_status_controller()->set_last_download_updates_result( |
| 132 download_result); |
| 133 if (download_result != SYNCER_OK) |
| 134 return true; |
| 135 } |
| 136 ApplyUpdates(session); |
| 137 |
| 138 if (ExitRequested()) { |
| 139 return false; |
| 140 } else { |
| 141 session->SendEventNotification(SyncEngineEvent::SYNC_CYCLE_ENDED); |
| 142 return true; |
| 143 } |
| 144 return SYNCER_OK; |
| 145 } |
| 146 |
| 147 void Syncer::ApplyUpdates(SyncSession* session) { |
| 148 TRACE_EVENT0("sync", "ApplyUpdates"); |
| 149 |
| 150 ApplyControlDataUpdates(session); |
| 151 |
| 152 ApplyUpdatesAndResolveConflictsCommand apply_updates; |
| 153 apply_updates.Execute(session); |
| 154 |
| 155 session->context()->set_hierarchy_conflict_detected( |
| 156 session->status_controller().num_hierarchy_conflicts() > 0); |
| 157 |
| 158 session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED); |
195 } | 159 } |
196 | 160 |
197 } // namespace syncer | 161 } // namespace syncer |
OLD | NEW |