Chromium Code Reviews| 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()) { |
|
tim (not reviewing)
2013/06/21 17:41:38
I think the general paradigm of "check ExitRequest
rlarocque
2013/06/21 18:30:36
IMO, we never should have defaulted to checking Ex
| |
| 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) |
|
tim (not reviewing)
2013/06/21 17:24:00
If ExitRequested is true, we can / should note tha
rlarocque
2013/06/21 18:30:36
Good point. I was trying to follow the same conve
| |
| 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; | |
|
tim (not reviewing)
2013/06/21 17:24:00
I don't think you meant to leave this here. I als
rlarocque
2013/06/21 18:30:36
The SyncShare variants have different parameters.
| |
| 145 } | |
| 146 | |
| 147 void Syncer::ApplyUpdates(SyncSession* session) { | |
| 148 TRACE_EVENT0("sync", "ApplyUpdates"); | |
| 149 | |
|
tim (not reviewing)
2013/06/21 17:24:00
What do you think about adding DCHECK(!ExitRequest
rlarocque
2013/06/21 18:30:36
I don't think a DCHECK() is would be safe... I'll
tim (not reviewing)
2013/06/21 21:24:03
Keep in mind that 90 milliseconds (as quoted above
| |
| 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 |