| OLD | NEW |
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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 "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h" | 5 #include "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
| 13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
| 14 #include "chrome/browser/sync/engine/conflict_resolution_view.h" | |
| 15 #include "chrome/browser/sync/engine/syncer_util.h" | 14 #include "chrome/browser/sync/engine/syncer_util.h" |
| 16 #include "chrome/browser/sync/engine/update_applicator.h" | 15 #include "chrome/browser/sync/engine/update_applicator.h" |
| 16 #include "chrome/browser/sync/sessions/sync_session.h" |
| 17 #include "chrome/browser/sync/syncable/directory_manager.h" | 17 #include "chrome/browser/sync/syncable/directory_manager.h" |
| 18 | 18 |
| 19 namespace browser_sync { | 19 namespace browser_sync { |
| 20 | 20 |
| 21 using sessions::ConflictProgress; |
| 22 using sessions::StatusController; |
| 23 using sessions::SyncSession; |
| 24 using sessions::UpdateProgress; |
| 21 using std::set; | 25 using std::set; |
| 22 using std::string; | 26 using std::string; |
| 23 using std::vector; | 27 using std::vector; |
| 24 | 28 |
| 25 BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSetsCommand() {} | 29 BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSetsCommand() {} |
| 26 BuildAndProcessConflictSetsCommand::~BuildAndProcessConflictSetsCommand() {} | 30 BuildAndProcessConflictSetsCommand::~BuildAndProcessConflictSetsCommand() {} |
| 27 | 31 |
| 28 void BuildAndProcessConflictSetsCommand::ModelChangingExecuteImpl( | 32 void BuildAndProcessConflictSetsCommand::ModelChangingExecuteImpl( |
| 29 SyncerSession* session) { | 33 SyncSession* session) { |
| 30 session->set_conflict_sets_built(BuildAndProcessConflictSets(session)); | 34 session->status_controller()->set_conflict_sets_built( |
| 35 BuildAndProcessConflictSets(session)); |
| 31 } | 36 } |
| 32 | 37 |
| 33 bool BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSets( | 38 bool BuildAndProcessConflictSetsCommand::BuildAndProcessConflictSets( |
| 34 SyncerSession* session) { | 39 SyncSession* session) { |
| 35 syncable::ScopedDirLookup dir(session->dirman(), session->account_name()); | 40 syncable::ScopedDirLookup dir(session->context()->directory_manager(), |
| 41 session->context()->account_name()); |
| 36 if (!dir.good()) | 42 if (!dir.good()) |
| 37 return false; | 43 return false; |
| 38 bool had_single_direction_sets = false; | 44 bool had_single_direction_sets = false; |
| 39 { // Scope for transaction. | 45 { // Scope for transaction. |
| 40 syncable::WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); | 46 syncable::WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); |
| 41 ConflictResolutionView conflict_view(session); | 47 BuildConflictSets(&trans, |
| 42 BuildConflictSets(&trans, &conflict_view); | 48 session->status_controller()->mutable_conflict_progress()); |
| 43 had_single_direction_sets = | 49 had_single_direction_sets = ProcessSingleDirectionConflictSets(&trans, |
| 44 ProcessSingleDirectionConflictSets(&trans, session); | 50 session->context()->resolver(), session->status_controller()); |
| 45 // We applied some updates transactionally, lets try syncing again. | 51 // We applied some updates transactionally, lets try syncing again. |
| 46 if (had_single_direction_sets) | 52 if (had_single_direction_sets) |
| 47 return true; | 53 return true; |
| 48 } | 54 } |
| 49 return false; | 55 return false; |
| 50 } | 56 } |
| 51 | 57 |
| 52 bool BuildAndProcessConflictSetsCommand::ProcessSingleDirectionConflictSets( | 58 bool BuildAndProcessConflictSetsCommand::ProcessSingleDirectionConflictSets( |
| 53 syncable::WriteTransaction* trans, SyncerSession* const session) { | 59 syncable::WriteTransaction* trans, ConflictResolver* resolver, |
| 60 StatusController* status) { |
| 54 bool rv = false; | 61 bool rv = false; |
| 55 ConflictResolutionView conflict_view(session); | |
| 56 set<ConflictSet*>::const_iterator all_sets_iterator; | 62 set<ConflictSet*>::const_iterator all_sets_iterator; |
| 57 for (all_sets_iterator = conflict_view.ConflictSetsBegin(); | 63 for (all_sets_iterator = status->conflict_progress()->ConflictSetsBegin(); |
| 58 all_sets_iterator != conflict_view.ConflictSetsEnd(); ) { | 64 all_sets_iterator != status->conflict_progress()->ConflictSetsEnd();) { |
| 59 const ConflictSet* conflict_set = *all_sets_iterator; | 65 const ConflictSet* conflict_set = *all_sets_iterator; |
| 60 CHECK(conflict_set->size() >= 2); | 66 CHECK(conflict_set->size() >= 2); |
| 61 // We scan the set to see if it consists of changes of only one type. | 67 // We scan the set to see if it consists of changes of only one type. |
| 62 ConflictSet::const_iterator i; | 68 ConflictSet::const_iterator i; |
| 63 size_t unsynced_count = 0, unapplied_count = 0; | 69 size_t unsynced_count = 0, unapplied_count = 0; |
| 64 for (i = conflict_set->begin(); i != conflict_set->end(); ++i) { | 70 for (i = conflict_set->begin(); i != conflict_set->end(); ++i) { |
| 65 syncable::Entry entry(trans, syncable::GET_BY_ID, *i); | 71 syncable::Entry entry(trans, syncable::GET_BY_ID, *i); |
| 66 CHECK(entry.good()); | 72 CHECK(entry.good()); |
| 67 if (entry.Get(syncable::IS_UNSYNCED)) | 73 if (entry.Get(syncable::IS_UNSYNCED)) |
| 68 unsynced_count++; | 74 unsynced_count++; |
| 69 if (entry.Get(syncable::IS_UNAPPLIED_UPDATE)) | 75 if (entry.Get(syncable::IS_UNAPPLIED_UPDATE)) |
| 70 unapplied_count++; | 76 unapplied_count++; |
| 71 } | 77 } |
| 72 if (conflict_set->size() == unsynced_count && 0 == unapplied_count) { | 78 if (conflict_set->size() == unsynced_count && 0 == unapplied_count) { |
| 73 LOG(INFO) << "Skipped transactional commit attempt."; | 79 LOG(INFO) << "Skipped transactional commit attempt."; |
| 74 } else if (conflict_set->size() == unapplied_count && | 80 } else if (conflict_set->size() == unapplied_count && 0 == unsynced_count && |
| 75 0 == unsynced_count && | 81 ApplyUpdatesTransactionally(trans, conflict_set, resolver, status)) { |
| 76 ApplyUpdatesTransactionally(trans, conflict_set, session)) { | |
| 77 rv = true; | 82 rv = true; |
| 78 } | 83 } |
| 79 ++all_sets_iterator; | 84 ++all_sets_iterator; |
| 80 } | 85 } |
| 81 return rv; | 86 return rv; |
| 82 } | 87 } |
| 83 | 88 |
| 84 namespace { | 89 namespace { |
| 85 | 90 |
| 86 void StoreLocalDataForUpdateRollback(syncable::Entry* entry, | 91 void StoreLocalDataForUpdateRollback(syncable::Entry* entry, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION)); | 123 entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION)); |
| 119 entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR)); | 124 entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR)); |
| 120 entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)); | 125 entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)); |
| 121 entry.Put(syncable::ID, backup->ref(syncable::ID)); | 126 entry.Put(syncable::ID, backup->ref(syncable::ID)); |
| 122 entry.Put(syncable::IS_UNAPPLIED_UPDATE, | 127 entry.Put(syncable::IS_UNAPPLIED_UPDATE, |
| 123 backup->ref(syncable::IS_UNAPPLIED_UPDATE)); | 128 backup->ref(syncable::IS_UNAPPLIED_UPDATE)); |
| 124 return true; | 129 return true; |
| 125 } | 130 } |
| 126 | 131 |
| 127 void PlaceEntriesAtRoot(syncable::WriteTransaction* trans, | 132 void PlaceEntriesAtRoot(syncable::WriteTransaction* trans, |
| 128 const vector<syncable::Id>* ids) { | 133 const vector<syncable::Id>* ids) { |
| 129 vector<syncable::Id>::const_iterator it; | 134 vector<syncable::Id>::const_iterator it; |
| 130 for (it = ids->begin(); it != ids->end(); ++it) { | 135 for (it = ids->begin(); it != ids->end(); ++it) { |
| 131 syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it); | 136 syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it); |
| 132 entry.Put(syncable::PARENT_ID, trans->root_id()); | 137 entry.Put(syncable::PARENT_ID, trans->root_id()); |
| 138 } |
| 133 } | 139 } |
| 134 } | |
| 135 | 140 |
| 136 } // namespace | 141 } // namespace |
| 137 | 142 |
| 138 bool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally( | 143 bool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally( |
| 139 syncable::WriteTransaction* trans, | 144 syncable::WriteTransaction* trans, |
| 140 const vector<syncable::Id>* const update_set, | 145 const vector<syncable::Id>* const update_set, |
| 141 SyncerSession* const session) { | 146 ConflictResolver* resolver, StatusController* status) { |
| 142 // The handles in the |update_set| order. | 147 // The handles in the |update_set| order. |
| 143 vector<int64> handles; | 148 vector<int64> handles; |
| 144 | 149 |
| 145 // Holds the same Ids as update_set, but sorted so that runs of adjacent | 150 // Holds the same Ids as update_set, but sorted so that runs of adjacent |
| 146 // nodes appear in order. | 151 // nodes appear in order. |
| 147 vector<syncable::Id> rollback_ids; | 152 vector<syncable::Id> rollback_ids; |
| 148 rollback_ids.reserve(update_set->size()); | 153 rollback_ids.reserve(update_set->size()); |
| 149 | 154 |
| 150 // Tracks what's added to |rollback_ids|. | 155 // Tracks what's added to |rollback_ids|. |
| 151 syncable::MetahandleSet rollback_ids_inserted_items; | 156 syncable::MetahandleSet rollback_ids_inserted_items; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 176 | 181 |
| 177 // 4. Use the preparer to move things to an initial starting state where | 182 // 4. Use the preparer to move things to an initial starting state where |
| 178 // nothing in the set is a child of anything else. If | 183 // nothing in the set is a child of anything else. If |
| 179 // we've correctly calculated the set, the server tree is valid and no | 184 // we've correctly calculated the set, the server tree is valid and no |
| 180 // changes have occurred locally we should be able to apply updates from this | 185 // changes have occurred locally we should be able to apply updates from this |
| 181 // state. | 186 // state. |
| 182 PlaceEntriesAtRoot(trans, update_set); | 187 PlaceEntriesAtRoot(trans, update_set); |
| 183 | 188 |
| 184 // 5. Use the usual apply updates from the special start state we've just | 189 // 5. Use the usual apply updates from the special start state we've just |
| 185 // prepared. | 190 // prepared. |
| 186 UpdateApplicator applicator(session->resolver(), handles.begin(), | 191 UpdateApplicator applicator(resolver, handles.begin(), handles.end()); |
| 187 handles.end()); | |
| 188 while (applicator.AttemptOneApplication(trans)) { | 192 while (applicator.AttemptOneApplication(trans)) { |
| 189 // Keep going till all updates are applied. | 193 // Keep going till all updates are applied. |
| 190 } | 194 } |
| 191 if (!applicator.AllUpdatesApplied()) { | 195 if (!applicator.AllUpdatesApplied()) { |
| 192 LOG(ERROR) << "Transactional Apply Failed, Rolling back."; | 196 LOG(ERROR) << "Transactional Apply Failed, Rolling back."; |
| 193 // We have to move entries into the temp dir again. e.g. if a swap was in a | 197 // We have to move entries into the temp dir again. e.g. if a swap was in a |
| 194 // set with other failing updates, the swap may have gone through, meaning | 198 // set with other failing updates, the swap may have gone through, meaning |
| 195 // the roll back needs to be transactional. But as we're going to a known | 199 // the roll back needs to be transactional. But as we're going to a known |
| 196 // good state we should always succeed. | 200 // good state we should always succeed. |
| 197 PlaceEntriesAtRoot(trans, update_set); | 201 PlaceEntriesAtRoot(trans, update_set); |
| 198 | 202 |
| 199 // Rollback all entries. | 203 // Rollback all entries. |
| 200 for (size_t i = 0; i < rollback_data.size(); ++i) { | 204 for (size_t i = 0; i < rollback_data.size(); ++i) { |
| 201 CHECK(RollbackEntry(trans, &rollback_data[i])); | 205 CHECK(RollbackEntry(trans, &rollback_data[i])); |
| 202 } | 206 } |
| 203 return false; // Don't save progress -- we just undid it. | 207 return false; // Don't save progress -- we just undid it. |
| 204 } | 208 } |
| 205 applicator.SaveProgressIntoSessionState(session); | 209 applicator.SaveProgressIntoSessionState(status->mutable_conflict_progress(), |
| 210 status->mutable_update_progress()); |
| 206 return true; | 211 return true; |
| 207 } | 212 } |
| 208 | 213 |
| 209 void BuildAndProcessConflictSetsCommand::BuildConflictSets( | 214 void BuildAndProcessConflictSetsCommand::BuildConflictSets( |
| 210 syncable::BaseTransaction* trans, | 215 syncable::BaseTransaction* trans, |
| 211 ConflictResolutionView* view) { | 216 ConflictProgress* conflict_progress) { |
| 212 view->CleanupSets(); | 217 conflict_progress->CleanupSets(); |
| 213 set<syncable::Id>::iterator i = view->CommitConflictsBegin(); | 218 set<syncable::Id>::iterator i = conflict_progress->ConflictingItemsBegin(); |
| 214 while (i != view->CommitConflictsEnd()) { | 219 while (i != conflict_progress->ConflictingItemsEnd()) { |
| 215 syncable::Entry entry(trans, syncable::GET_BY_ID, *i); | 220 syncable::Entry entry(trans, syncable::GET_BY_ID, *i); |
| 216 CHECK(entry.good()); | 221 CHECK(entry.good()); |
| 217 if (!entry.Get(syncable::IS_UNSYNCED) && | 222 if (!entry.Get(syncable::IS_UNSYNCED) && |
| 218 !entry.Get(syncable::IS_UNAPPLIED_UPDATE)) { | 223 !entry.Get(syncable::IS_UNAPPLIED_UPDATE)) { |
| 219 // This can happen very rarely. It means we had a simply conflicting item | 224 // This can happen very rarely. It means we had a simply conflicting item |
| 220 // that randomly committed. We drop the entry as it's no longer | 225 // that randomly committed. We drop the entry as it's no longer |
| 221 // conflicting. | 226 // conflicting. |
| 222 view->EraseCommitConflict(i++); | 227 conflict_progress->EraseConflictingItemById(*(i++)); |
| 223 continue; | 228 continue; |
| 224 } | 229 } |
| 225 if (entry.ExistsOnClientBecauseNameIsNonEmpty() && | 230 if (entry.ExistsOnClientBecauseNameIsNonEmpty() && |
| 226 (entry.Get(syncable::IS_DEL) || entry.Get(syncable::SERVER_IS_DEL))) { | 231 (entry.Get(syncable::IS_DEL) || entry.Get(syncable::SERVER_IS_DEL))) { |
| 227 // If we're deleted on client or server we can't be in a complex set. | 232 // If we're deleted on client or server we can't be in a complex set. |
| 228 ++i; | 233 ++i; |
| 229 continue; | 234 continue; |
| 230 } | 235 } |
| 231 bool new_parent = | 236 bool new_parent = |
| 232 entry.Get(syncable::PARENT_ID) != entry.Get(syncable::SERVER_PARENT_ID); | 237 entry.Get(syncable::PARENT_ID) != entry.Get(syncable::SERVER_PARENT_ID); |
| 233 if (new_parent) | 238 if (new_parent) |
| 234 MergeSetsForIntroducedLoops(trans, &entry, view); | 239 MergeSetsForIntroducedLoops(trans, &entry, conflict_progress); |
| 235 MergeSetsForNonEmptyDirectories(trans, &entry, view); | 240 MergeSetsForNonEmptyDirectories(trans, &entry, conflict_progress); |
| 236 ++i; | 241 ++i; |
| 237 } | 242 } |
| 238 } | 243 } |
| 239 | 244 |
| 240 void BuildAndProcessConflictSetsCommand::MergeSetsForIntroducedLoops( | 245 void BuildAndProcessConflictSetsCommand::MergeSetsForIntroducedLoops( |
| 241 syncable::BaseTransaction* trans, syncable::Entry* entry, | 246 syncable::BaseTransaction* trans, syncable::Entry* entry, |
| 242 ConflictResolutionView* view) { | 247 ConflictProgress* conflict_progress) { |
| 243 // This code crawls up from the item in question until it gets to the root | 248 // This code crawls up from the item in question until it gets to the root |
| 244 // or itself. If it gets to the root it does nothing. If it finds a loop all | 249 // or itself. If it gets to the root it does nothing. If it finds a loop all |
| 245 // moved unsynced entries in the list of crawled entries have their sets | 250 // moved unsynced entries in the list of crawled entries have their sets |
| 246 // merged with the entry. | 251 // merged with the entry. |
| 247 // TODO(sync): Build test cases to cover this function when the argument list | 252 // TODO(sync): Build test cases to cover this function when the argument list |
| 248 // has settled. | 253 // has settled. |
| 249 syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); | 254 syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); |
| 250 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); | 255 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); |
| 251 if (!parent.good()) { | 256 if (!parent.good()) { |
| 252 return; | 257 return; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 266 entry->Get(syncable::PARENT_ID) != | 271 entry->Get(syncable::PARENT_ID) != |
| 267 entry->Get(syncable::SERVER_PARENT_ID)) | 272 entry->Get(syncable::SERVER_PARENT_ID)) |
| 268 conflicting_entries.push_back(parent_id); | 273 conflicting_entries.push_back(parent_id); |
| 269 parent_id = parent.Get(syncable::PARENT_ID); | 274 parent_id = parent.Get(syncable::PARENT_ID); |
| 270 if (parent_id == entry->Get(syncable::ID)) | 275 if (parent_id == entry->Get(syncable::ID)) |
| 271 break; | 276 break; |
| 272 } | 277 } |
| 273 if (parent_id.IsRoot()) | 278 if (parent_id.IsRoot()) |
| 274 return; | 279 return; |
| 275 for (size_t i = 0; i < conflicting_entries.size(); i++) { | 280 for (size_t i = 0; i < conflicting_entries.size(); i++) { |
| 276 view->MergeSets(entry->Get(syncable::ID), conflicting_entries[i]); | 281 conflict_progress->MergeSets(entry->Get(syncable::ID), |
| 282 conflicting_entries[i]); |
| 277 } | 283 } |
| 278 } | 284 } |
| 279 | 285 |
| 280 namespace { | 286 namespace { |
| 281 | 287 |
| 282 class ServerDeletedPathChecker { | 288 class ServerDeletedPathChecker { |
| 283 public: | 289 public: |
| 284 static bool CausingConflict(const syncable::Entry& e, | 290 static bool CausingConflict(const syncable::Entry& e, |
| 285 const syncable::Entry& log_entry) { | 291 const syncable::Entry& log_entry) { |
| 286 CHECK(e.good()) << "Missing parent in path of: " << log_entry; | 292 CHECK(e.good()) << "Missing parent in path of: " << log_entry; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 syncable::Id parent_id = parent.Get(syncable::PARENT_ID); | 335 syncable::Id parent_id = parent.Get(syncable::PARENT_ID); |
| 330 if (parent_id == check_id) | 336 if (parent_id == check_id) |
| 331 return syncable::kNullId; | 337 return syncable::kNullId; |
| 332 return parent_id; | 338 return parent_id; |
| 333 } | 339 } |
| 334 }; | 340 }; |
| 335 | 341 |
| 336 template <typename Checker> | 342 template <typename Checker> |
| 337 void CrawlDeletedTreeMergingSets(syncable::BaseTransaction* trans, | 343 void CrawlDeletedTreeMergingSets(syncable::BaseTransaction* trans, |
| 338 const syncable::Entry& entry, | 344 const syncable::Entry& entry, |
| 339 ConflictResolutionView* view, | 345 ConflictProgress* conflict_progress, |
| 340 Checker checker) { | 346 Checker checker) { |
| 341 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); | 347 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); |
| 342 syncable::Id double_step_parent_id = parent_id; | 348 syncable::Id double_step_parent_id = parent_id; |
| 343 // This block builds sets where we've got an entry in a directory the server | 349 // This block builds sets where we've got an entry in a directory the server |
| 344 // wants to delete. | 350 // wants to delete. |
| 345 // | 351 // |
| 346 // Here we're walking up the tree to find all entries that the pass checks | 352 // Here we're walking up the tree to find all entries that the pass checks |
| 347 // deleted. We can be extremely strict here as anything unexpected means | 353 // deleted. We can be extremely strict here as anything unexpected means |
| 348 // invariants in the local hierarchy have been broken. | 354 // invariants in the local hierarchy have been broken. |
| 349 while (!parent_id.IsRoot()) { | 355 while (!parent_id.IsRoot()) { |
| 350 if (!double_step_parent_id.IsRoot()) { | 356 if (!double_step_parent_id.IsRoot()) { |
| 351 // Checks to ensure we don't loop. | 357 // Checks to ensure we don't loop. |
| 352 double_step_parent_id = checker.GetAndExamineParent( | 358 double_step_parent_id = checker.GetAndExamineParent( |
| 353 trans, double_step_parent_id, parent_id, entry); | 359 trans, double_step_parent_id, parent_id, entry); |
| 354 double_step_parent_id = checker.GetAndExamineParent( | 360 double_step_parent_id = checker.GetAndExamineParent( |
| 355 trans, double_step_parent_id, parent_id, entry); | 361 trans, double_step_parent_id, parent_id, entry); |
| 356 } | 362 } |
| 357 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); | 363 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); |
| 358 if (checker.CausingConflict(parent, entry)) | 364 if (checker.CausingConflict(parent, entry)) { |
| 359 view->MergeSets(entry.Get(syncable::ID), parent.Get(syncable::ID)); | 365 conflict_progress->MergeSets(entry.Get(syncable::ID), |
| 360 else | 366 parent.Get(syncable::ID)); |
| 367 } else { |
| 361 break; | 368 break; |
| 369 } |
| 362 parent_id = parent.Get(syncable::PARENT_ID); | 370 parent_id = parent.Get(syncable::PARENT_ID); |
| 363 } | 371 } |
| 364 } | 372 } |
| 365 | 373 |
| 366 } // namespace | 374 } // namespace |
| 367 | 375 |
| 368 void BuildAndProcessConflictSetsCommand::MergeSetsForNonEmptyDirectories( | 376 void BuildAndProcessConflictSetsCommand::MergeSetsForNonEmptyDirectories( |
| 369 syncable::BaseTransaction* trans, syncable::Entry* entry, | 377 syncable::BaseTransaction* trans, syncable::Entry* entry, |
| 370 ConflictResolutionView* view) { | 378 ConflictProgress* conflict_progress) { |
| 371 if (entry->Get(syncable::IS_UNSYNCED) && !entry->Get(syncable::IS_DEL)) { | 379 if (entry->Get(syncable::IS_UNSYNCED) && !entry->Get(syncable::IS_DEL)) { |
| 372 ServerDeletedPathChecker checker; | 380 ServerDeletedPathChecker checker; |
| 373 CrawlDeletedTreeMergingSets(trans, *entry, view, checker); | 381 CrawlDeletedTreeMergingSets(trans, *entry, conflict_progress, checker); |
| 374 } | 382 } |
| 375 if (entry->Get(syncable::IS_UNAPPLIED_UPDATE) && | 383 if (entry->Get(syncable::IS_UNAPPLIED_UPDATE) && |
| 376 !entry->Get(syncable::SERVER_IS_DEL)) { | 384 !entry->Get(syncable::SERVER_IS_DEL)) { |
| 377 syncable::Entry parent(trans, syncable::GET_BY_ID, | 385 syncable::Entry parent(trans, syncable::GET_BY_ID, |
| 378 entry->Get(syncable::SERVER_PARENT_ID)); | 386 entry->Get(syncable::SERVER_PARENT_ID)); |
| 379 syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); | 387 syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); |
| 380 if (!parent.good()) | 388 if (!parent.good()) |
| 381 return; | 389 return; |
| 382 LocallyDeletedPathChecker checker; | 390 LocallyDeletedPathChecker checker; |
| 383 if (!checker.CausingConflict(parent, *entry)) | 391 if (!checker.CausingConflict(parent, *entry)) |
| 384 return; | 392 return; |
| 385 view->MergeSets(entry->Get(syncable::ID), parent.Get(syncable::ID)); | 393 conflict_progress->MergeSets(entry->Get(syncable::ID), |
| 386 CrawlDeletedTreeMergingSets(trans, parent, view, checker); | 394 parent.Get(syncable::ID)); |
| 395 CrawlDeletedTreeMergingSets(trans, parent, conflict_progress, checker); |
| 387 } | 396 } |
| 388 } | 397 } |
| 389 | 398 |
| 390 } // namespace browser_sync | 399 } // namespace browser_sync |
| OLD | NEW |