| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "sync/engine/update_applicator.h" |
| |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "sync/engine/syncer_util.h" |
| #include "sync/syncable/entry.h" |
| #include "sync/syncable/mutable_entry.h" |
| #include "sync/syncable/syncable_id.h" |
| #include "sync/syncable/syncable_write_transaction.h" |
| |
| using std::vector; |
| |
| namespace syncer { |
| |
| using syncable::ID; |
| |
| UpdateApplicator::UpdateApplicator(Cryptographer* cryptographer) |
| : cryptographer_(cryptographer), |
| updates_applied_(0), |
| encryption_conflicts_(0), |
| hierarchy_conflicts_(0) { |
| } |
| |
| UpdateApplicator::~UpdateApplicator() { |
| } |
| |
| // Attempt to apply all updates, using multiple passes if necessary. |
| // |
| // Some updates must be applied in order. For example, children must be created |
| // after their parent folder is created. This function runs an O(n^2) algorithm |
| // that will keep trying until there is nothing left to apply, or it stops |
| // making progress, which would indicate that the hierarchy is invalid. |
| // |
| // The update applicator also has to deal with simple conflicts, which occur |
| // when an item is modified on both the server and the local model. We remember |
| // their IDs so they can be passed to the conflict resolver after all the other |
| // applications are complete. |
| // |
| // Finally, there are encryption conflicts, which can occur when we don't have |
| // access to all the Nigori keys. There's nothing we can do about them here. |
| void UpdateApplicator::AttemptApplications( |
| syncable::WriteTransaction* trans, |
| const std::vector<int64>& handles) { |
| std::vector<int64> to_apply = handles; |
| |
| DVLOG(1) << "UpdateApplicator running over " << to_apply.size() << " items."; |
| while (!to_apply.empty()) { |
| std::vector<int64> to_reapply; |
| |
| for (std::vector<int64>::iterator i = to_apply.begin(); |
| i != to_apply.end(); ++i) { |
| syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *i); |
| UpdateAttemptResponse result = AttemptToUpdateEntry( |
| trans, &entry, cryptographer_); |
| |
| switch (result) { |
| case SUCCESS: |
| updates_applied_++; |
| break; |
| case CONFLICT_SIMPLE: |
| simple_conflict_ids_.insert(entry.GetId()); |
| break; |
| case CONFLICT_ENCRYPTION: |
| encryption_conflicts_++; |
| break; |
| case CONFLICT_HIERARCHY: |
| // The decision to classify these as hierarchy conflcits is tentative. |
| // If we make any progress this round, we'll clear the hierarchy |
| // conflict count and attempt to reapply these updates. |
| to_reapply.push_back(*i); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| if (to_reapply.size() == to_apply.size()) { |
| // We made no progress. Must be stubborn hierarchy conflicts. |
| hierarchy_conflicts_ = to_apply.size(); |
| break; |
| } |
| |
| // We made some progress, so prepare for what might be another iteration. |
| // If everything went well, to_reapply will be empty and we'll break out on |
| // the while condition. |
| to_apply.swap(to_reapply); |
| to_reapply.clear(); |
| } |
| } |
| |
| } // namespace syncer |