| 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  | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   85  |   85  | 
|   86 void StoreLocalDataForUpdateRollback(syncable::Entry* entry, |   86 void StoreLocalDataForUpdateRollback(syncable::Entry* entry, | 
|   87                                      syncable::EntryKernel* backup) { |   87                                      syncable::EntryKernel* backup) { | 
|   88   CHECK(!entry->Get(syncable::IS_UNSYNCED)) << " Storing Rollback data for " |   88   CHECK(!entry->Get(syncable::IS_UNSYNCED)) << " Storing Rollback data for " | 
|   89       "entry that's unsynced." << *entry; |   89       "entry that's unsynced." << *entry; | 
|   90   CHECK(entry->Get(syncable::IS_UNAPPLIED_UPDATE)) << " Storing Rollback data " |   90   CHECK(entry->Get(syncable::IS_UNAPPLIED_UPDATE)) << " Storing Rollback data " | 
|   91       "for entry that's not an unapplied update." << *entry; |   91       "for entry that's not an unapplied update." << *entry; | 
|   92   *backup = entry->GetKernelCopy(); |   92   *backup = entry->GetKernelCopy(); | 
|   93 } |   93 } | 
|   94  |   94  | 
|   95 class UniqueNameGenerator { |  | 
|   96  public: |  | 
|   97   void Initialize() { |  | 
|   98     // To avoid name collisions we prefix the names with hex data derived from |  | 
|   99     // 64 bits of randomness. |  | 
|  100     int64 name_prefix = static_cast<int64>(base::RandUint64()); |  | 
|  101     name_stem_ = StringPrintf("%0" PRId64 "x.", name_prefix); |  | 
|  102   } |  | 
|  103   string StringNameForEntry(const syncable::Entry& entry) { |  | 
|  104     CHECK(!name_stem_.empty()); |  | 
|  105     std::stringstream rv; |  | 
|  106     rv << name_stem_ << entry.Get(syncable::ID); |  | 
|  107     return rv.str(); |  | 
|  108   } |  | 
|  109   PathString PathStringNameForEntry(const syncable::Entry& entry) { |  | 
|  110     string name = StringNameForEntry(entry); |  | 
|  111     return PathString(name.begin(), name.end()); |  | 
|  112   } |  | 
|  113  |  | 
|  114  private: |  | 
|  115   string name_stem_; |  | 
|  116 }; |  | 
|  117  |   95  | 
|  118 bool RollbackEntry(syncable::WriteTransaction* trans, |   96 bool RollbackEntry(syncable::WriteTransaction* trans, | 
|  119                    syncable::EntryKernel* backup) { |   97                    syncable::EntryKernel* backup) { | 
|  120   syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, |   98   syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, | 
|  121                                backup->ref(syncable::META_HANDLE)); |   99                                backup->ref(syncable::META_HANDLE)); | 
|  122   CHECK(entry.good()); |  100   CHECK(entry.good()); | 
|  123  |  101  | 
|  124   if (!entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL))) |  102   if (!entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL))) | 
|  125     return false; |  103     return false; | 
|  126   syncable::Name name = syncable::Name::FromEntryKernel(backup); |  104  | 
|  127   if (!entry.PutParentIdAndName(backup->ref(syncable::PARENT_ID), name)) |  105   entry.Put(syncable::NON_UNIQUE_NAME, backup->ref(syncable::NON_UNIQUE_NAME)); | 
|  128     return false; |  106   entry.Put(syncable::PARENT_ID, backup->ref(syncable::PARENT_ID)); | 
|  129  |  107  | 
|  130   if (!backup->ref(syncable::IS_DEL)) { |  108   if (!backup->ref(syncable::IS_DEL)) { | 
|  131     if (!entry.PutPredecessor(backup->ref(syncable::PREV_ID))) |  109     if (!entry.PutPredecessor(backup->ref(syncable::PREV_ID))) | 
|  132       return false; |  110       return false; | 
|  133   } |  111   } | 
|  134  |  112  | 
|  135   if (backup->ref(syncable::PREV_ID) != entry.Get(syncable::PREV_ID)) |  113   if (backup->ref(syncable::PREV_ID) != entry.Get(syncable::PREV_ID)) | 
|  136     return false; |  114     return false; | 
|  137  |  115  | 
|  138   entry.Put(syncable::CTIME, backup->ref(syncable::CTIME)); |  116   entry.Put(syncable::CTIME, backup->ref(syncable::CTIME)); | 
|  139   entry.Put(syncable::MTIME, backup->ref(syncable::MTIME)); |  117   entry.Put(syncable::MTIME, backup->ref(syncable::MTIME)); | 
|  140   entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION)); |  118   entry.Put(syncable::BASE_VERSION, backup->ref(syncable::BASE_VERSION)); | 
|  141   entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR)); |  119   entry.Put(syncable::IS_DIR, backup->ref(syncable::IS_DIR)); | 
|  142   entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)); |  120   entry.Put(syncable::IS_DEL, backup->ref(syncable::IS_DEL)); | 
|  143   entry.Put(syncable::ID, backup->ref(syncable::ID)); |  121   entry.Put(syncable::ID, backup->ref(syncable::ID)); | 
|  144   entry.Put(syncable::IS_UNAPPLIED_UPDATE, |  122   entry.Put(syncable::IS_UNAPPLIED_UPDATE, | 
|  145             backup->ref(syncable::IS_UNAPPLIED_UPDATE)); |  123             backup->ref(syncable::IS_UNAPPLIED_UPDATE)); | 
|  146   return true; |  124   return true; | 
|  147 } |  125 } | 
|  148  |  126  | 
|  149 class TransactionalUpdateEntryPreparer { |  127 void PlaceEntriesAtRoot(syncable::WriteTransaction* trans, | 
|  150  public: |  128                         const vector<syncable::Id>* ids) { | 
|  151   TransactionalUpdateEntryPreparer() { |  129   vector<syncable::Id>::const_iterator it; | 
|  152     namegen_.Initialize(); |  130   for (it = ids->begin(); it != ids->end(); ++it) { | 
 |  131     syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it); | 
 |  132     entry.Put(syncable::PARENT_ID, trans->root_id()); | 
|  153   } |  133   } | 
|  154  |  134 } | 
|  155   void PrepareEntries(syncable::WriteTransaction* trans, |  | 
|  156                       const vector<syncable::Id>* ids) { |  | 
|  157     vector<syncable::Id>::const_iterator it; |  | 
|  158     for (it = ids->begin(); it != ids->end(); ++it) { |  | 
|  159       syncable::MutableEntry entry(trans, syncable::GET_BY_ID, *it); |  | 
|  160       syncable::Name random_name(namegen_.PathStringNameForEntry(entry)); |  | 
|  161       CHECK(entry.PutParentIdAndName(trans->root_id(), random_name)); |  | 
|  162     } |  | 
|  163   } |  | 
|  164  |  | 
|  165  private: |  | 
|  166   UniqueNameGenerator namegen_; |  | 
|  167   DISALLOW_COPY_AND_ASSIGN(TransactionalUpdateEntryPreparer); |  | 
|  168 }; |  | 
|  169  |  135  | 
|  170 }  // namespace |  136 }  // namespace | 
|  171  |  137  | 
|  172 bool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally( |  138 bool BuildAndProcessConflictSetsCommand::ApplyUpdatesTransactionally( | 
|  173     syncable::WriteTransaction* trans, |  139     syncable::WriteTransaction* trans, | 
|  174     const vector<syncable::Id>* const update_set, |  140     const vector<syncable::Id>* const update_set, | 
|  175     SyncerSession* const session) { |  141     SyncerSession* const session) { | 
|  176   // The handles in the |update_set| order. |  142   // The handles in the |update_set| order. | 
|  177   vector<int64> handles; |  143   vector<int64> handles; | 
|  178  |  144  | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
|  201   DCHECK_EQ(rollback_ids_inserted_items.size(), update_set->size()); |  167   DCHECK_EQ(rollback_ids_inserted_items.size(), update_set->size()); | 
|  202  |  168  | 
|  203   // 3. Store the information needed to rollback if the transaction fails. |  169   // 3. Store the information needed to rollback if the transaction fails. | 
|  204   // Do this before modifying anything to keep the next/prev values intact. |  170   // Do this before modifying anything to keep the next/prev values intact. | 
|  205   vector<syncable::EntryKernel> rollback_data(rollback_ids.size()); |  171   vector<syncable::EntryKernel> rollback_data(rollback_ids.size()); | 
|  206   for (size_t i = 0; i < rollback_ids.size(); ++i) { |  172   for (size_t i = 0; i < rollback_ids.size(); ++i) { | 
|  207     syncable::Entry entry(trans, syncable::GET_BY_ID, rollback_ids[i]); |  173     syncable::Entry entry(trans, syncable::GET_BY_ID, rollback_ids[i]); | 
|  208     StoreLocalDataForUpdateRollback(&entry, &rollback_data[i]); |  174     StoreLocalDataForUpdateRollback(&entry, &rollback_data[i]); | 
|  209   } |  175   } | 
|  210  |  176  | 
|  211   // 4. Use the preparer to move things to an initial starting state where no |  177   // 4. Use the preparer to move things to an initial starting state where | 
|  212   // names collide, and nothing in the set is a child of anything else.  If |  178   // nothing in the set is a child of anything else.  If | 
|  213   // we've correctly calculated the set, the server tree is valid and no |  179   // we've correctly calculated the set, the server tree is valid and no | 
|  214   // changes have occurred locally we should be able to apply updates from this |  180   // changes have occurred locally we should be able to apply updates from this | 
|  215   // state. |  181   // state. | 
|  216   TransactionalUpdateEntryPreparer preparer; |  182   PlaceEntriesAtRoot(trans, update_set); | 
|  217   preparer.PrepareEntries(trans, update_set); |  | 
|  218  |  183  | 
|  219   // 5. Use the usual apply updates from the special start state we've just |  184   // 5. Use the usual apply updates from the special start state we've just | 
|  220   // prepared. |  185   // prepared. | 
|  221   UpdateApplicator applicator(session->resolver(), handles.begin(), |  186   UpdateApplicator applicator(session->resolver(), handles.begin(), | 
|  222                               handles.end()); |  187                               handles.end()); | 
|  223   while (applicator.AttemptOneApplication(trans)) { |  188   while (applicator.AttemptOneApplication(trans)) { | 
|  224     // Keep going till all updates are applied. |  189     // Keep going till all updates are applied. | 
|  225   } |  190   } | 
|  226   if (!applicator.AllUpdatesApplied()) { |  191   if (!applicator.AllUpdatesApplied()) { | 
|  227     LOG(ERROR) << "Transactional Apply Failed, Rolling back."; |  192     LOG(ERROR) << "Transactional Apply Failed, Rolling back."; | 
|  228     // We have to move entries into the temp dir again. e.g. if a swap was in a |  193     // We have to move entries into the temp dir again. e.g. if a swap was in a | 
|  229     // set with other failing updates, the swap may have gone through, meaning |  194     // set with other failing updates, the swap may have gone through, meaning | 
|  230     // the roll back needs to be transactional. But as we're going to a known |  195     // the roll back needs to be transactional. But as we're going to a known | 
|  231     // good state we should always succeed. |  196     // good state we should always succeed. | 
|  232     preparer.PrepareEntries(trans, update_set); |  197     PlaceEntriesAtRoot(trans, update_set); | 
|  233  |  198  | 
|  234     // Rollback all entries. |  199     // Rollback all entries. | 
|  235     for (size_t i = 0; i < rollback_data.size(); ++i) { |  200     for (size_t i = 0; i < rollback_data.size(); ++i) { | 
|  236       CHECK(RollbackEntry(trans, &rollback_data[i])); |  201       CHECK(RollbackEntry(trans, &rollback_data[i])); | 
|  237     } |  202     } | 
|  238     return false;  // Don't save progress -- we just undid it. |  203     return false;  // Don't save progress -- we just undid it. | 
|  239   } |  204   } | 
|  240   applicator.SaveProgressIntoSessionState(session); |  205   applicator.SaveProgressIntoSessionState(session); | 
|  241   return true; |  206   return true; | 
|  242 } |  207 } | 
|  243  |  208  | 
|  244 void BuildAndProcessConflictSetsCommand::BuildConflictSets( |  209 void BuildAndProcessConflictSetsCommand::BuildConflictSets( | 
|  245     syncable::BaseTransaction* trans, |  210     syncable::BaseTransaction* trans, | 
|  246     ConflictResolutionView* view) { |  211     ConflictResolutionView* view) { | 
|  247   view->CleanupSets(); |  212   view->CleanupSets(); | 
|  248   set<syncable::Id>::iterator i = view->CommitConflictsBegin(); |  213   set<syncable::Id>::iterator i = view->CommitConflictsBegin(); | 
|  249   while (i != view->CommitConflictsEnd()) { |  214   while (i != view->CommitConflictsEnd()) { | 
|  250     syncable::Entry entry(trans, syncable::GET_BY_ID, *i); |  215     syncable::Entry entry(trans, syncable::GET_BY_ID, *i); | 
|  251     CHECK(entry.good()); |  216     CHECK(entry.good()); | 
|  252     if (!entry.Get(syncable::IS_UNSYNCED) && |  217     if (!entry.Get(syncable::IS_UNSYNCED) && | 
|  253         !entry.Get(syncable::IS_UNAPPLIED_UPDATE)) { |  218         !entry.Get(syncable::IS_UNAPPLIED_UPDATE)) { | 
|  254       // This can happen very rarely. It means we had a simply conflicting item |  219       // This can happen very rarely. It means we had a simply conflicting item | 
|  255       // that randomly committed. We drop the entry as it's no longer |  220       // that randomly committed. We drop the entry as it's no longer | 
|  256       // conflicting. |  221       // conflicting. | 
|  257       view->EraseCommitConflict(i++); |  222       view->EraseCommitConflict(i++); | 
|  258       continue; |  223       continue; | 
|  259     } |  224     } | 
|  260     if (entry.ExistsOnClientBecauseDatabaseNameIsNonEmpty() && |  225     if (entry.ExistsOnClientBecauseNameIsNonEmpty() && | 
|  261        (entry.Get(syncable::IS_DEL) || entry.Get(syncable::SERVER_IS_DEL))) { |  226        (entry.Get(syncable::IS_DEL) || entry.Get(syncable::SERVER_IS_DEL))) { | 
|  262        // If we're deleted on client or server we can't be in a complex set. |  227        // If we're deleted on client or server we can't be in a complex set. | 
|  263       ++i; |  228       ++i; | 
|  264       continue; |  229       continue; | 
|  265     } |  230     } | 
|  266     bool new_parent = |  231     bool new_parent = | 
|  267         entry.Get(syncable::PARENT_ID) != entry.Get(syncable::SERVER_PARENT_ID); |  232         entry.Get(syncable::PARENT_ID) != entry.Get(syncable::SERVER_PARENT_ID); | 
|  268     bool new_name = 0 != syncable::ComparePathNames(entry.GetSyncNameValue(), |  | 
|  269                                           entry.Get(syncable::SERVER_NAME)); |  | 
|  270     if (new_parent || new_name) |  | 
|  271       MergeSetsForNameClash(trans, &entry, view); |  | 
|  272     if (new_parent) |  233     if (new_parent) | 
|  273       MergeSetsForIntroducedLoops(trans, &entry, view); |  234       MergeSetsForIntroducedLoops(trans, &entry, view); | 
|  274     MergeSetsForNonEmptyDirectories(trans, &entry, view); |  235     MergeSetsForNonEmptyDirectories(trans, &entry, view); | 
|  275     ++i; |  236     ++i; | 
|  276   } |  237   } | 
|  277 } |  238 } | 
|  278  |  239  | 
|  279 void BuildAndProcessConflictSetsCommand::MergeSetsForNameClash( |  | 
|  280     syncable::BaseTransaction* trans, syncable::Entry* entry, |  | 
|  281     ConflictResolutionView* view) { |  | 
|  282   PathString server_name = entry->Get(syncable::SERVER_NAME); |  | 
|  283   // Uncommitted entries have no server name. We trap this because the root |  | 
|  284   // item has a null name and 0 parentid. |  | 
|  285   if (server_name.empty()) |  | 
|  286     return; |  | 
|  287   syncable::Id conflicting_id = |  | 
|  288       SyncerUtil::GetNameConflictingItemId( |  | 
|  289           trans, entry->Get(syncable::SERVER_PARENT_ID), server_name); |  | 
|  290   if (syncable::kNullId != conflicting_id) |  | 
|  291     view->MergeSets(entry->Get(syncable::ID), conflicting_id); |  | 
|  292 } |  | 
|  293  |  | 
|  294 void BuildAndProcessConflictSetsCommand::MergeSetsForIntroducedLoops( |  240 void BuildAndProcessConflictSetsCommand::MergeSetsForIntroducedLoops( | 
|  295     syncable::BaseTransaction* trans, syncable::Entry* entry, |  241     syncable::BaseTransaction* trans, syncable::Entry* entry, | 
|  296     ConflictResolutionView* view) { |  242     ConflictResolutionView* view) { | 
|  297   // This code crawls up from the item in question until it gets to the root |  243   // This code crawls up from the item in question until it gets to the root | 
|  298   // or itself. If it gets to the root it does nothing. If it finds a loop all |  244   // or itself. If it gets to the root it does nothing. If it finds a loop all | 
|  299   // moved unsynced entries in the list of crawled entries have their sets |  245   // moved unsynced entries in the list of crawled entries have their sets | 
|  300   // merged with the entry. |  246   // merged with the entry. | 
|  301   // TODO(sync): Build test cases to cover this function when the argument list |  247   // TODO(sync): Build test cases to cover this function when the argument list | 
|  302   // has settled. |  248   // has settled. | 
|  303   syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); |  249   syncable::Id parent_id = entry->Get(syncable::SERVER_PARENT_ID); | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  435       return; |  381       return; | 
|  436     LocallyDeletedPathChecker checker; |  382     LocallyDeletedPathChecker checker; | 
|  437     if (!checker.CausingConflict(parent, *entry)) |  383     if (!checker.CausingConflict(parent, *entry)) | 
|  438       return; |  384       return; | 
|  439     view->MergeSets(entry->Get(syncable::ID), parent.Get(syncable::ID)); |  385     view->MergeSets(entry->Get(syncable::ID), parent.Get(syncable::ID)); | 
|  440     CrawlDeletedTreeMergingSets(trans, parent, view, checker); |  386     CrawlDeletedTreeMergingSets(trans, parent, view, checker); | 
|  441   } |  387   } | 
|  442 } |  388 } | 
|  443  |  389  | 
|  444 }  // namespace browser_sync |  390 }  // namespace browser_sync | 
| OLD | NEW |