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
3 // found in the LICENSE file.
5 #include "sync/engine/update_applicator.h"
9 #include "base/logging.h"
10 #include "sync/engine/syncer_util.h"
11 #include "sync/sessions/session_state.h"
12 #include "sync/syncable/entry.h"
13 #include "sync/syncable/mutable_entry.h"
14 #include "sync/syncable/syncable_id.h"
15 #include "sync/syncable/write_transaction.h"
21 UpdateApplicator::UpdateApplicator(ConflictResolver
* resolver
,
22 Cryptographer
* cryptographer
,
23 const UpdateIterator
& begin
,
24 const UpdateIterator
& end
,
25 const ModelSafeRoutingInfo
& routes
,
26 ModelSafeGroup group_filter
)
27 : resolver_(resolver
),
28 cryptographer_(cryptographer
),
32 group_filter_(group_filter
),
34 routing_info_(routes
),
35 application_results_(end
- begin
) {
36 size_t item_count
= end
- begin
;
37 DVLOG(1) << "UpdateApplicator created for " << item_count
<< " items.";
40 UpdateApplicator::~UpdateApplicator() {
43 // Returns true if there's more to do.
44 bool UpdateApplicator::AttemptOneApplication(
45 syncable::WriteTransaction
* trans
) {
46 // If there are no updates left to consider, we're done.
49 if (pointer_
== end_
) {
53 DVLOG(1) << "UpdateApplicator doing additional pass.";
57 // Clear the tracked failures to avoid double-counting.
58 application_results_
.ClearConflicts();
61 syncable::Entry
read_only(trans
, syncable::GET_BY_HANDLE
, *pointer_
);
62 if (SkipUpdate(read_only
)) {
67 syncable::MutableEntry
entry(trans
, syncable::GET_BY_HANDLE
, *pointer_
);
68 UpdateAttemptResponse updateResponse
= AttemptToUpdateEntry(
69 trans
, &entry
, resolver_
, cryptographer_
);
70 switch (updateResponse
) {
74 application_results_
.AddSuccess(entry
.Get(syncable::ID
));
78 application_results_
.AddSimpleConflict(entry
.Get(syncable::ID
));
80 case CONFLICT_ENCRYPTION
:
82 application_results_
.AddEncryptionConflict(entry
.Get(syncable::ID
));
84 case CONFLICT_HIERARCHY
:
86 application_results_
.AddHierarchyConflict(entry
.Get(syncable::ID
));
92 DVLOG(1) << "Apply Status for " << entry
.Get(syncable::META_HANDLE
)
93 << " is " << updateResponse
;
98 void UpdateApplicator::Advance() {
103 bool UpdateApplicator::SkipUpdate(const syncable::Entry
& entry
) {
104 syncer::ModelType type
= entry
.GetServerModelType();
105 ModelSafeGroup g
= GetGroupForModelType(type
, routing_info_
);
106 // The set of updates passed to the UpdateApplicator should already
107 // be group-filtered.
108 if (g
!= group_filter_
) {
112 if (g
== GROUP_PASSIVE
&&
113 !routing_info_
.count(type
) &&
114 type
!= syncer::UNSPECIFIED
&&
115 type
!= syncer::TOP_LEVEL_FOLDER
) {
116 DVLOG(1) << "Skipping update application, type not permitted.";
122 bool UpdateApplicator::AllUpdatesApplied() const {
123 return application_results_
.no_conflicts() && begin_
== end_
;
126 void UpdateApplicator::SaveProgressIntoSessionState(
127 sessions::ConflictProgress
* conflict_progress
,
128 sessions::UpdateProgress
* update_progress
) {
129 DCHECK(begin_
== end_
|| ((pointer_
== end_
) && !progress_
))
130 << "SaveProgress called before updates exhausted.";
132 application_results_
.SaveProgress(conflict_progress
, update_progress
);
135 UpdateApplicator::ResultTracker::ResultTracker(size_t num_results
) {
136 successful_ids_
.reserve(num_results
);
139 UpdateApplicator::ResultTracker::~ResultTracker() {
142 void UpdateApplicator::ResultTracker::AddSimpleConflict(syncable::Id id
) {
143 conflicting_ids_
.push_back(id
);
146 void UpdateApplicator::ResultTracker::AddEncryptionConflict(syncable::Id id
) {
147 encryption_conflict_ids_
.push_back(id
);
150 void UpdateApplicator::ResultTracker::AddHierarchyConflict(syncable::Id id
) {
151 hierarchy_conflict_ids_
.push_back(id
);
154 void UpdateApplicator::ResultTracker::AddSuccess(syncable::Id id
) {
155 successful_ids_
.push_back(id
);
158 void UpdateApplicator::ResultTracker::SaveProgress(
159 sessions::ConflictProgress
* conflict_progress
,
160 sessions::UpdateProgress
* update_progress
) {
161 vector
<syncable::Id
>::const_iterator i
;
162 for (i
= conflicting_ids_
.begin(); i
!= conflicting_ids_
.end(); ++i
) {
163 conflict_progress
->AddSimpleConflictingItemById(*i
);
164 update_progress
->AddAppliedUpdate(CONFLICT_SIMPLE
, *i
);
166 for (i
= encryption_conflict_ids_
.begin();
167 i
!= encryption_conflict_ids_
.end(); ++i
) {
168 conflict_progress
->AddEncryptionConflictingItemById(*i
);
169 update_progress
->AddAppliedUpdate(CONFLICT_ENCRYPTION
, *i
);
171 for (i
= hierarchy_conflict_ids_
.begin();
172 i
!= hierarchy_conflict_ids_
.end(); ++i
) {
173 conflict_progress
->AddHierarchyConflictingItemById(*i
);
174 update_progress
->AddAppliedUpdate(CONFLICT_HIERARCHY
, *i
);
176 for (i
= successful_ids_
.begin(); i
!= successful_ids_
.end(); ++i
) {
177 conflict_progress
->EraseSimpleConflictingItemById(*i
);
178 update_progress
->AddAppliedUpdate(SUCCESS
, *i
);
182 void UpdateApplicator::ResultTracker::ClearConflicts() {
183 conflicting_ids_
.clear();
184 encryption_conflict_ids_
.clear();
185 hierarchy_conflict_ids_
.clear();
188 bool UpdateApplicator::ResultTracker::no_conflicts() const {
189 return conflicting_ids_
.empty();
192 } // namespace syncer