1// Copyright (c) 2010 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 "chrome/browser/sync/engine/update_applicator.h" 6 7#include <vector> 8 9#include "base/logging.h" 10#include "chrome/browser/sync/engine/syncer_util.h" 11#include "chrome/browser/sync/sessions/session_state.h" 12#include "chrome/browser/sync/syncable/syncable.h" 13#include "chrome/browser/sync/syncable/syncable_id.h" 14 15using std::vector; 16 17namespace browser_sync { 18 19UpdateApplicator::UpdateApplicator(ConflictResolver* resolver, 20 Cryptographer* cryptographer, 21 const UpdateIterator& begin, 22 const UpdateIterator& end, 23 const ModelSafeRoutingInfo& routes, 24 ModelSafeGroup group_filter) 25 : resolver_(resolver), 26 cryptographer_(cryptographer), 27 begin_(begin), 28 end_(end), 29 pointer_(begin), 30 group_filter_(group_filter), 31 progress_(false), 32 routing_info_(routes) { 33 size_t item_count = end - begin; 34 VLOG(1) << "UpdateApplicator created for " << item_count << " items."; 35 successful_ids_.reserve(item_count); 36 } 37 38UpdateApplicator::~UpdateApplicator() { 39} 40 41// Returns true if there's more to do. 42bool UpdateApplicator::AttemptOneApplication( 43 syncable::WriteTransaction* trans) { 44 // If there are no updates left to consider, we're done. 45 if (end_ == begin_) 46 return false; 47 if (pointer_ == end_) { 48 if (!progress_) 49 return false; 50 51 VLOG(1) << "UpdateApplicator doing additional pass."; 52 pointer_ = begin_; 53 progress_ = false; 54 55 // Clear the tracked failures to avoid double-counting. 56 conflicting_ids_.clear(); 57 } 58 59 syncable::Entry read_only(trans, syncable::GET_BY_HANDLE, *pointer_); 60 if (SkipUpdate(read_only)) { 61 Advance(); 62 return true; 63 } 64 65 syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *pointer_); 66 UpdateAttemptResponse updateResponse = SyncerUtil::AttemptToUpdateEntry( 67 trans, &entry, resolver_, cryptographer_); 68 switch (updateResponse) { 69 case SUCCESS: 70 Advance(); 71 progress_ = true; 72 successful_ids_.push_back(entry.Get(syncable::ID)); 73 break; 74 case CONFLICT: 75 pointer_++; 76 conflicting_ids_.push_back(entry.Get(syncable::ID)); 77 break; 78 default: 79 NOTREACHED(); 80 break; 81 } 82 VLOG(1) << "Apply Status for " << entry.Get(syncable::META_HANDLE) 83 << " is " << updateResponse; 84 85 return true; 86} 87 88void UpdateApplicator::Advance() { 89 --end_; 90 *pointer_ = *end_; 91} 92 93bool UpdateApplicator::SkipUpdate(const syncable::Entry& entry) { 94 syncable::ModelType type = entry.GetServerModelType(); 95 ModelSafeGroup g = GetGroupForModelType(type, routing_info_); 96 // The extra routing_info count check here is to support GetUpdateses for 97 // a subset of the globally enabled types, and not attempt to update items 98 // if their type isn't permitted in the current run. These would typically 99 // be unapplied items from a previous sync. 100 if (g != group_filter_) 101 return true; 102 if (g == GROUP_PASSIVE && 103 !routing_info_.count(type) && 104 type != syncable::UNSPECIFIED && 105 type != syncable::TOP_LEVEL_FOLDER) { 106 VLOG(1) << "Skipping update application, type not permitted."; 107 return true; 108 } 109 return false; 110} 111 112bool UpdateApplicator::AllUpdatesApplied() const { 113 return conflicting_ids_.empty() && begin_ == end_; 114} 115 116void UpdateApplicator::SaveProgressIntoSessionState( 117 sessions::ConflictProgress* conflict_progress, 118 sessions::UpdateProgress* update_progress) { 119 DCHECK(begin_ == end_ || ((pointer_ == end_) && !progress_)) 120 << "SaveProgress called before updates exhausted."; 121 122 vector<syncable::Id>::const_iterator i; 123 for (i = conflicting_ids_.begin(); i != conflicting_ids_.end(); ++i) { 124 conflict_progress->AddConflictingItemById(*i); 125 update_progress->AddAppliedUpdate(CONFLICT, *i); 126 } 127 for (i = successful_ids_.begin(); i != successful_ids_.end(); ++i) { 128 conflict_progress->EraseConflictingItemById(*i); 129 update_progress->AddAppliedUpdate(SUCCESS, *i); 130 } 131} 132 133} // namespace browser_sync 134