1 // Copyright 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. 4 5 #include "sync/engine/update_applicator.h" 6 7 #include <vector> 8 9 #include "base/logging.h" 10 #include "sync/engine/syncer_util.h" 11 #include "sync/syncable/entry.h" 12 #include "sync/syncable/mutable_entry.h" 13 #include "sync/syncable/syncable_id.h" 14 #include "sync/syncable/syncable_write_transaction.h" 15 16 using std::vector; 17 18 namespace syncer { 19 20 using syncable::ID; 21 22 UpdateApplicator::UpdateApplicator(Cryptographer* cryptographer) 23 : cryptographer_(cryptographer), 24 updates_applied_(0), 25 encryption_conflicts_(0), 26 hierarchy_conflicts_(0) { 27 } 28 29 UpdateApplicator::~UpdateApplicator() { 30 } 31 32 // Attempt to apply all updates, using multiple passes if necessary. 33 // 34 // Some updates must be applied in order. For example, children must be created 35 // after their parent folder is created. This function runs an O(n^2) algorithm 36 // that will keep trying until there is nothing left to apply, or it stops 37 // making progress, which would indicate that the hierarchy is invalid. 38 // 39 // The update applicator also has to deal with simple conflicts, which occur 40 // when an item is modified on both the server and the local model. We remember 41 // their IDs so they can be passed to the conflict resolver after all the other 42 // applications are complete. 43 // 44 // Finally, there are encryption conflicts, which can occur when we don't have 45 // access to all the Nigori keys. There's nothing we can do about them here. 46 void UpdateApplicator::AttemptApplications( 47 syncable::WriteTransaction* trans, 48 const std::vector<int64>& handles) { 49 std::vector<int64> to_apply = handles; 50 51 DVLOG(1) << "UpdateApplicator running over " << to_apply.size() << " items."; 52 while (!to_apply.empty()) { 53 std::vector<int64> to_reapply; 54 55 for (std::vector<int64>::iterator i = to_apply.begin(); 56 i != to_apply.end(); ++i) { 57 syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *i); 58 UpdateAttemptResponse result = AttemptToUpdateEntry( 59 trans, &entry, cryptographer_); 60 61 switch (result) { 62 case SUCCESS: 63 updates_applied_++; 64 break; 65 case CONFLICT_SIMPLE: 66 simple_conflict_ids_.insert(entry.GetId()); 67 break; 68 case CONFLICT_ENCRYPTION: 69 encryption_conflicts_++; 70 break; 71 case CONFLICT_HIERARCHY: 72 // The decision to classify these as hierarchy conflcits is tentative. 73 // If we make any progress this round, we'll clear the hierarchy 74 // conflict count and attempt to reapply these updates. 75 to_reapply.push_back(*i); 76 break; 77 default: 78 NOTREACHED(); 79 break; 80 } 81 } 82 83 if (to_reapply.size() == to_apply.size()) { 84 // We made no progress. Must be stubborn hierarchy conflicts. 85 hierarchy_conflicts_ = to_apply.size(); 86 break; 87 } 88 89 // We made some progress, so prepare for what might be another iteration. 90 // If everything went well, to_reapply will be empty and we'll break out on 91 // the while condition. 92 to_apply.swap(to_reapply); 93 to_reapply.clear(); 94 } 95 } 96 97 } // namespace syncer 98