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
15 using std::vector;
16
17 namespace browser_sync {
18
UpdateApplicator(ConflictResolver * resolver,Cryptographer * cryptographer,const UpdateIterator & begin,const UpdateIterator & end,const ModelSafeRoutingInfo & routes,ModelSafeGroup group_filter)19 UpdateApplicator::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
~UpdateApplicator()38 UpdateApplicator::~UpdateApplicator() {
39 }
40
41 // Returns true if there's more to do.
AttemptOneApplication(syncable::WriteTransaction * trans)42 bool 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
Advance()88 void UpdateApplicator::Advance() {
89 --end_;
90 *pointer_ = *end_;
91 }
92
SkipUpdate(const syncable::Entry & entry)93 bool 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
AllUpdatesApplied() const112 bool UpdateApplicator::AllUpdatesApplied() const {
113 return conflicting_ids_.empty() && begin_ == end_;
114 }
115
SaveProgressIntoSessionState(sessions::ConflictProgress * conflict_progress,sessions::UpdateProgress * update_progress)116 void 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