Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: sync/engine/update_applicator.cc

Issue 10964057: sync: Refactor update application (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix an include Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "sync/engine/update_applicator.h" 5 #include "sync/engine/update_applicator.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "sync/engine/syncer_util.h" 10 #include "sync/engine/syncer_util.h"
11 #include "sync/sessions/session_state.h" 11 #include "sync/sessions/session_state.h"
12 #include "sync/syncable/entry.h" 12 #include "sync/syncable/entry.h"
13 #include "sync/syncable/mutable_entry.h" 13 #include "sync/syncable/mutable_entry.h"
14 #include "sync/syncable/syncable_id.h" 14 #include "sync/syncable/syncable_id.h"
15 #include "sync/syncable/write_transaction.h" 15 #include "sync/syncable/write_transaction.h"
16 16
17 using std::vector; 17 using std::vector;
18 18
19 namespace syncer { 19 namespace syncer {
20 20
21 UpdateApplicator::UpdateApplicator(ConflictResolver* resolver, 21 using syncable::ID;
22 Cryptographer* cryptographer, 22
23 const UpdateIterator& begin, 23 UpdateApplicator::UpdateApplicator(Cryptographer* cryptographer,
24 const UpdateIterator& end,
25 const ModelSafeRoutingInfo& routes, 24 const ModelSafeRoutingInfo& routes,
26 ModelSafeGroup group_filter) 25 ModelSafeGroup group_filter)
27 : resolver_(resolver), 26 : cryptographer_(cryptographer),
28 cryptographer_(cryptographer),
29 begin_(begin),
30 end_(end),
31 pointer_(begin),
32 group_filter_(group_filter), 27 group_filter_(group_filter),
33 progress_(false),
34 routing_info_(routes), 28 routing_info_(routes),
35 application_results_(end - begin) { 29 application_results_() {
36 size_t item_count = end - begin;
37 DVLOG(1) << "UpdateApplicator created for " << item_count << " items.";
38 } 30 }
39 31
40 UpdateApplicator::~UpdateApplicator() { 32 UpdateApplicator::~UpdateApplicator() {
41 } 33 }
42 34
43 // Returns true if there's more to do. 35 // Attempt to apply all updates, using multiple passes if necessary.
44 bool UpdateApplicator::AttemptOneApplication( 36 //
45 syncable::WriteTransaction* trans) { 37 // Some updates must be applied in order. For example, children must be created
46 // If there are no updates left to consider, we're done. 38 // after their parent folder is created. This function runs an O(n^2) algorithm
47 if (end_ == begin_) 39 // that will keep trying until there is nothing left to apply, or it stops
48 return false; 40 // making progress, which would indicate that the hierarchy is invalid.
49 if (pointer_ == end_) { 41 //
50 if (!progress_) 42 // The update applicator also has to deal with simple conflicts, which occur
51 return false; 43 // when an item is modified on both the server and the local model, and
44 // encryption conflicts. There's not much we can do about them here, so we
45 // don't bother re-processing them on subsequent passes.
46 void UpdateApplicator::AttemptApplications(
47 syncable::WriteTransaction* trans,
48 std::vector<int64> to_apply) {
49 DVLOG(1) << "UpdateApplicator running over " << to_apply.size() << " items.";
50 while (!to_apply.empty()) {
51 std::vector<int64> to_reapply;
52 52
53 DVLOG(1) << "UpdateApplicator doing additional pass."; 53 for (UpdateIterator i = to_apply.begin(); i != to_apply.end(); ++i) {
54 pointer_ = begin_; 54 syncable::Entry read_entry(trans, syncable::GET_BY_HANDLE, *i);
55 progress_ = false; 55 if (SkipUpdate(read_entry)) {
56 continue;
57 }
56 58
57 // Clear the tracked failures to avoid double-counting. 59 syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *i);
58 application_results_.ClearConflicts(); 60 UpdateAttemptResponse result = AttemptToUpdateEntry(
61 trans, &entry, cryptographer_);
62
63 switch (result) {
64 case SUCCESS:
65 application_results_.AddSuccess(entry.Get(ID));
66 break;
67 case CONFLICT_SIMPLE:
68 application_results_.AddSimpleConflict(entry.Get(ID));
69 break;
70 case CONFLICT_ENCRYPTION:
71 application_results_.AddEncryptionConflict(entry.Get(ID));
72 break;
73 case CONFLICT_HIERARCHY:
74 // Tentatively label these as hierarchy conflicts. If we make any
75 // progress this round, we'll unlabel it and try to re-apply.
76 application_results_.AddHierarchyConflict(entry.Get(ID));
77 to_reapply.push_back(*i);
78 break;
79 default:
80 NOTREACHED();
81 break;
82 }
83 }
84
85 if (to_reapply.size() == to_apply.size()) {
86 // We made no progress. Must be stubborn hierarchy conflicts.
87 break;
rlarocque 2012/09/25 17:37:45 I don't like this, but I think it's cleaner than a
tim (not reviewing) 2012/09/26 21:13:14 If we have unapplied updates for type T in the Dir
rlarocque 2012/09/26 21:32:29 I don't think so, though I admit I had not anticip
88 } else {
89 application_results_.ClearHierarchyConflicts();
90 }
91
92 to_apply = to_reapply;
akalin 2012/09/25 22:00:55 not sure what this line does
rlarocque 2012/09/25 22:16:46 I'm using the parameter as if it were a function-s
akalin 2012/09/25 22:22:24 oh, i missed that it was inside the while loop. Y
59 } 93 }
60
61 syncable::Entry read_only(trans, syncable::GET_BY_HANDLE, *pointer_);
62 if (SkipUpdate(read_only)) {
63 Advance();
64 return true;
65 }
66
67 syncable::MutableEntry entry(trans, syncable::GET_BY_HANDLE, *pointer_);
68 UpdateAttemptResponse updateResponse = AttemptToUpdateEntry(
69 trans, &entry, resolver_, cryptographer_);
70 switch (updateResponse) {
71 case SUCCESS:
72 Advance();
73 progress_ = true;
74 application_results_.AddSuccess(entry.Get(syncable::ID));
75 break;
76 case CONFLICT_SIMPLE:
77 pointer_++;
78 application_results_.AddSimpleConflict(entry.Get(syncable::ID));
79 break;
80 case CONFLICT_ENCRYPTION:
81 pointer_++;
82 application_results_.AddEncryptionConflict(entry.Get(syncable::ID));
83 break;
84 case CONFLICT_HIERARCHY:
85 pointer_++;
86 application_results_.AddHierarchyConflict(entry.Get(syncable::ID));
87 break;
88 default:
89 NOTREACHED();
90 break;
91 }
92 DVLOG(1) << "Apply Status for " << entry.Get(syncable::META_HANDLE)
93 << " is " << updateResponse;
94
95 return true;
96 }
97
98 void UpdateApplicator::Advance() {
99 --end_;
100 *pointer_ = *end_;
101 } 94 }
102 95
103 bool UpdateApplicator::SkipUpdate(const syncable::Entry& entry) { 96 bool UpdateApplicator::SkipUpdate(const syncable::Entry& entry) {
104 ModelType type = entry.GetServerModelType(); 97 ModelType type = entry.GetServerModelType();
105 ModelSafeGroup g = GetGroupForModelType(type, routing_info_); 98 ModelSafeGroup g = GetGroupForModelType(type, routing_info_);
106 // The set of updates passed to the UpdateApplicator should already 99 // The set of updates passed to the UpdateApplicator should already
107 // be group-filtered. 100 // be group-filtered.
108 if (g != group_filter_) { 101 if (g != group_filter_) {
109 NOTREACHED(); 102 NOTREACHED();
110 return true; 103 return true;
111 } 104 }
112 if (g == GROUP_PASSIVE && 105 if (g == GROUP_PASSIVE &&
113 !routing_info_.count(type) && 106 !routing_info_.count(type) &&
114 type != UNSPECIFIED && 107 type != UNSPECIFIED &&
115 type != TOP_LEVEL_FOLDER) { 108 type != TOP_LEVEL_FOLDER) {
116 DVLOG(1) << "Skipping update application, type not permitted."; 109 DVLOG(1) << "Skipping update application, type not permitted.";
117 return true; 110 return true;
118 } 111 }
119 return false; 112 return false;
120 } 113 }
121 114
122 bool UpdateApplicator::AllUpdatesApplied() const {
123 return application_results_.no_conflicts() && begin_ == end_;
124 }
125
126 void UpdateApplicator::SaveProgressIntoSessionState( 115 void UpdateApplicator::SaveProgressIntoSessionState(
127 sessions::ConflictProgress* conflict_progress, 116 sessions::ConflictProgress* conflict_progress,
128 sessions::UpdateProgress* update_progress) { 117 sessions::UpdateProgress* update_progress) {
129 DCHECK(begin_ == end_ || ((pointer_ == end_) && !progress_))
130 << "SaveProgress called before updates exhausted.";
131
132 application_results_.SaveProgress(conflict_progress, update_progress); 118 application_results_.SaveProgress(conflict_progress, update_progress);
133 } 119 }
134 120
135 UpdateApplicator::ResultTracker::ResultTracker(size_t num_results) { 121 UpdateApplicator::ResultTracker::ResultTracker() {
136 successful_ids_.reserve(num_results);
137 } 122 }
138 123
139 UpdateApplicator::ResultTracker::~ResultTracker() { 124 UpdateApplicator::ResultTracker::~ResultTracker() {
140 } 125 }
141 126
142 void UpdateApplicator::ResultTracker::AddSimpleConflict(syncable::Id id) { 127 void UpdateApplicator::ResultTracker::AddSimpleConflict(syncable::Id id) {
143 conflicting_ids_.push_back(id); 128 conflicting_ids_.insert(id);
144 } 129 }
145 130
146 void UpdateApplicator::ResultTracker::AddEncryptionConflict(syncable::Id id) { 131 void UpdateApplicator::ResultTracker::AddEncryptionConflict(syncable::Id id) {
147 encryption_conflict_ids_.push_back(id); 132 encryption_conflict_ids_.insert(id);
148 } 133 }
149 134
150 void UpdateApplicator::ResultTracker::AddHierarchyConflict(syncable::Id id) { 135 void UpdateApplicator::ResultTracker::AddHierarchyConflict(syncable::Id id) {
151 hierarchy_conflict_ids_.push_back(id); 136 hierarchy_conflict_ids_.insert(id);
152 } 137 }
153 138
154 void UpdateApplicator::ResultTracker::AddSuccess(syncable::Id id) { 139 void UpdateApplicator::ResultTracker::AddSuccess(syncable::Id id) {
155 successful_ids_.push_back(id); 140 successful_ids_.insert(id);
156 } 141 }
157 142
158 void UpdateApplicator::ResultTracker::SaveProgress( 143 void UpdateApplicator::ResultTracker::SaveProgress(
159 sessions::ConflictProgress* conflict_progress, 144 sessions::ConflictProgress* conflict_progress,
160 sessions::UpdateProgress* update_progress) { 145 sessions::UpdateProgress* update_progress) {
161 vector<syncable::Id>::const_iterator i; 146 std::set<syncable::Id>::const_iterator i;
162 for (i = conflicting_ids_.begin(); i != conflicting_ids_.end(); ++i) { 147 for (i = conflicting_ids_.begin(); i != conflicting_ids_.end(); ++i) {
163 conflict_progress->AddSimpleConflictingItemById(*i); 148 conflict_progress->AddSimpleConflictingItemById(*i);
164 update_progress->AddAppliedUpdate(CONFLICT_SIMPLE, *i); 149 update_progress->AddAppliedUpdate(CONFLICT_SIMPLE, *i);
165 } 150 }
166 for (i = encryption_conflict_ids_.begin(); 151 for (i = encryption_conflict_ids_.begin();
167 i != encryption_conflict_ids_.end(); ++i) { 152 i != encryption_conflict_ids_.end(); ++i) {
168 conflict_progress->AddEncryptionConflictingItemById(*i); 153 conflict_progress->AddEncryptionConflictingItemById(*i);
169 update_progress->AddAppliedUpdate(CONFLICT_ENCRYPTION, *i); 154 update_progress->AddAppliedUpdate(CONFLICT_ENCRYPTION, *i);
170 } 155 }
171 for (i = hierarchy_conflict_ids_.begin(); 156 for (i = hierarchy_conflict_ids_.begin();
172 i != hierarchy_conflict_ids_.end(); ++i) { 157 i != hierarchy_conflict_ids_.end(); ++i) {
173 conflict_progress->AddHierarchyConflictingItemById(*i); 158 conflict_progress->AddHierarchyConflictingItemById(*i);
174 update_progress->AddAppliedUpdate(CONFLICT_HIERARCHY, *i); 159 update_progress->AddAppliedUpdate(CONFLICT_HIERARCHY, *i);
175 } 160 }
176 for (i = successful_ids_.begin(); i != successful_ids_.end(); ++i) { 161 for (i = successful_ids_.begin(); i != successful_ids_.end(); ++i) {
177 conflict_progress->EraseSimpleConflictingItemById(*i); 162 conflict_progress->EraseSimpleConflictingItemById(*i);
178 update_progress->AddAppliedUpdate(SUCCESS, *i); 163 update_progress->AddAppliedUpdate(SUCCESS, *i);
179 } 164 }
180 } 165 }
181 166
182 void UpdateApplicator::ResultTracker::ClearConflicts() { 167 void UpdateApplicator::ResultTracker::ClearHierarchyConflicts() {
183 conflicting_ids_.clear();
184 encryption_conflict_ids_.clear();
185 hierarchy_conflict_ids_.clear(); 168 hierarchy_conflict_ids_.clear();
186 } 169 }
187 170
188 bool UpdateApplicator::ResultTracker::no_conflicts() const { 171 bool UpdateApplicator::ResultTracker::no_conflicts() const {
189 return conflicting_ids_.empty(); 172 return conflicting_ids_.empty();
190 } 173 }
191 174
192 } // namespace syncer 175 } // namespace syncer
OLDNEW
« sync/engine/update_applicator.h ('K') | « sync/engine/update_applicator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698