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

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

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 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
OLDNEW
(Empty)
1 // Copyright 2014 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 "sync/engine/directory_update_handler.h"
6
7 #include <stdint.h>
8
9 #include <vector>
10
11 #include "sync/engine/conflict_resolver.h"
12 #include "sync/engine/process_updates_util.h"
13 #include "sync/engine/update_applicator.h"
14 #include "sync/sessions/directory_type_debug_info_emitter.h"
15 #include "sync/syncable/directory.h"
16 #include "sync/syncable/model_neutral_mutable_entry.h"
17 #include "sync/syncable/syncable_changes_version.h"
18 #include "sync/syncable/syncable_model_neutral_write_transaction.h"
19 #include "sync/syncable/syncable_write_transaction.h"
20 #include "sync/util/data_type_histogram.h"
21
22 namespace syncer {
23
24 using syncable::SYNCER;
25
26 DirectoryUpdateHandler::DirectoryUpdateHandler(
27 syncable::Directory* dir,
28 ModelType type,
29 scoped_refptr<ModelSafeWorker> worker,
30 DirectoryTypeDebugInfoEmitter* debug_info_emitter)
31 : dir_(dir),
32 type_(type),
33 worker_(worker),
34 debug_info_emitter_(debug_info_emitter) {}
35
36 DirectoryUpdateHandler::~DirectoryUpdateHandler() {}
37
38 bool DirectoryUpdateHandler::IsInitialSyncEnded() const {
39 return dir_->InitialSyncEndedForType(type_);
40 }
41
42 void DirectoryUpdateHandler::GetDownloadProgress(
43 sync_pb::DataTypeProgressMarker* progress_marker) const {
44 dir_->GetDownloadProgress(type_, progress_marker);
45 }
46
47 void DirectoryUpdateHandler::GetDataTypeContext(
48 sync_pb::DataTypeContext* context) const {
49 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
50 dir_->GetDataTypeContext(&trans, type_, context);
51 }
52
53 SyncerError DirectoryUpdateHandler::ProcessGetUpdatesResponse(
54 const sync_pb::DataTypeProgressMarker& progress_marker,
55 const sync_pb::DataTypeContext& mutated_context,
56 const SyncEntityList& applicable_updates,
57 sessions::StatusController* status) {
58 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
59 if (progress_marker.ByteSize() > 0) {
60 SyncRecordDatatypeBin("DataUse.Sync.ProgressMarker.Bytes",
61 ModelTypeToHistogramInt(type_),
62 progress_marker.ByteSize());
63 }
64 if (mutated_context.has_context()) {
65 sync_pb::DataTypeContext local_context;
66 dir_->GetDataTypeContext(&trans, type_, &local_context);
67
68 // Only update the local context if it is still relevant. If the local
69 // version is higher, it means a local change happened while the mutation
70 // was in flight, and the local context takes priority.
71 if (mutated_context.version() >= local_context.version() &&
72 local_context.context() != mutated_context.context()) {
73 dir_->SetDataTypeContext(&trans, type_, mutated_context);
74 // TODO(zea): trigger the datatype's UpdateDataTypeContext method.
75 } else if (mutated_context.version() < local_context.version()) {
76 // A GetUpdates using the old context was in progress when the context was
77 // set. Fail this get updates cycle, to force a retry.
78 DVLOG(1) << "GU Context conflict detected, forcing GU retry.";
79 debug_info_emitter_->EmitUpdateCountersUpdate();
80 return DATATYPE_TRIGGERED_RETRY;
81 }
82 }
83
84 // Auto-create permanent folder for the type if the progress marker
85 // changes from empty to non-empty.
86 if (IsTypeWithClientGeneratedRoot(type_) &&
87 dir_->HasEmptyDownloadProgress(type_) &&
88 IsValidProgressMarker(progress_marker)) {
89 CreateTypeRoot(&trans);
90 }
91
92 UpdateSyncEntities(&trans, applicable_updates, status);
93
94 if (IsValidProgressMarker(progress_marker)) {
95 ExpireEntriesIfNeeded(&trans, progress_marker);
96 UpdateProgressMarker(progress_marker);
97 }
98
99 debug_info_emitter_->EmitUpdateCountersUpdate();
100 return SYNCER_OK;
101 }
102
103 void DirectoryUpdateHandler::CreateTypeRoot(
104 syncable::ModelNeutralWriteTransaction* trans) {
105 syncable::ModelNeutralMutableEntry entry(
106 trans, syncable::CREATE_NEW_TYPE_ROOT, type_);
107 if (!entry.good()) {
108 // This will fail only if matching entry already exists, for example
109 // if the type gets disabled and its progress marker gets cleared,
110 // then the type gets re-enabled again.
111 DVLOG(1) << "Type root folder " << ModelTypeToRootTag(type_)
112 << " already exists.";
113 return;
114 }
115
116 entry.PutServerIsDir(true);
117 entry.PutUniqueServerTag(ModelTypeToRootTag(type_));
118 }
119
120 void DirectoryUpdateHandler::ApplyUpdates(sessions::StatusController* status) {
121 if (IsApplyUpdatesRequired()) {
122 // This will invoke handlers that belong to the model and its thread, so we
123 // switch to the appropriate thread before we start this work.
124 WorkCallback c =
125 base::Bind(&DirectoryUpdateHandler::ApplyUpdatesImpl,
126 // We wait until the callback is executed. We can safely use
127 // Unretained.
128 base::Unretained(this), base::Unretained(status));
129 worker_->DoWorkAndWaitUntilDone(c);
130
131 debug_info_emitter_->EmitUpdateCountersUpdate();
132 debug_info_emitter_->EmitStatusCountersUpdate();
133 }
134
135 PostApplyUpdates();
136 }
137
138 void DirectoryUpdateHandler::PassiveApplyUpdates(
139 sessions::StatusController* status) {
140 if (IsApplyUpdatesRequired()) {
141 // Just do the work here instead of deferring to another thread.
142 ApplyUpdatesImpl(status);
143
144 debug_info_emitter_->EmitUpdateCountersUpdate();
145 debug_info_emitter_->EmitStatusCountersUpdate();
146 }
147
148 PostApplyUpdates();
149 }
150
151 SyncerError DirectoryUpdateHandler::ApplyUpdatesImpl(
152 sessions::StatusController* status) {
153 syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir_);
154
155 std::vector<int64_t> handles;
156 dir_->GetUnappliedUpdateMetaHandles(
157 &trans,
158 FullModelTypeSet(type_),
159 &handles);
160
161 // First set of update application passes.
162 UpdateApplicator applicator(dir_->GetCryptographer(&trans));
163 applicator.AttemptApplications(&trans, handles);
164
165 // The old StatusController counters.
166 status->increment_num_updates_applied_by(applicator.updates_applied());
167 status->increment_num_hierarchy_conflicts_by(
168 applicator.hierarchy_conflicts());
169 status->increment_num_encryption_conflicts_by(
170 applicator.encryption_conflicts());
171
172 // The new UpdateCounter counters.
173 UpdateCounters* counters = debug_info_emitter_->GetMutableUpdateCounters();
174 counters->num_updates_applied += applicator.updates_applied();
175 counters->num_hierarchy_conflict_application_failures =
176 applicator.hierarchy_conflicts();
177 counters->num_encryption_conflict_application_failures +=
178 applicator.encryption_conflicts();
179
180 if (applicator.simple_conflict_ids().size() != 0) {
181 // Resolve the simple conflicts we just detected.
182 ConflictResolver resolver;
183 resolver.ResolveConflicts(&trans,
184 dir_->GetCryptographer(&trans),
185 applicator.simple_conflict_ids(),
186 status,
187 counters);
188
189 // Conflict resolution sometimes results in more updates to apply.
190 handles.clear();
191 dir_->GetUnappliedUpdateMetaHandles(
192 &trans,
193 FullModelTypeSet(type_),
194 &handles);
195
196 UpdateApplicator conflict_applicator(dir_->GetCryptographer(&trans));
197 conflict_applicator.AttemptApplications(&trans, handles);
198
199 // We count the number of updates from both applicator passes.
200 status->increment_num_updates_applied_by(
201 conflict_applicator.updates_applied());
202 counters->num_updates_applied += conflict_applicator.updates_applied();
203
204 // Encryption conflicts should remain unchanged by the resolution of simple
205 // conflicts. Those can only be solved by updating our nigori key bag.
206 DCHECK_EQ(conflict_applicator.encryption_conflicts(),
207 applicator.encryption_conflicts());
208
209 // Hierarchy conflicts should also remain unchanged, for reasons that are
210 // more subtle. Hierarchy conflicts exist when the application of a pending
211 // update from the server would make the local folder hierarchy
212 // inconsistent. The resolution of simple conflicts could never affect the
213 // hierarchy conflicting item directly, because hierarchy conflicts are not
214 // processed by the conflict resolver. It could, in theory, modify the
215 // local hierarchy on which hierarchy conflict detection depends. However,
216 // the conflict resolution algorithm currently in use does not allow this.
217 DCHECK_EQ(conflict_applicator.hierarchy_conflicts(),
218 applicator.hierarchy_conflicts());
219
220 // There should be no simple conflicts remaining. We know this because the
221 // resolver should have resolved all the conflicts we detected last time
222 // and, by the two previous assertions, that no conflicts have been
223 // downgraded from encryption or hierarchy down to simple.
224 DCHECK(conflict_applicator.simple_conflict_ids().empty());
225 }
226
227 return SYNCER_OK;
228 }
229
230 void DirectoryUpdateHandler::PostApplyUpdates() {
231 // If this is a type with client generated root, the root node has been
232 // created locally and didn't go through ApplyUpdatesImpl.
233 // Mark it as having the initial download completed so that the type
234 // reports as properly initialized (which is done by changing the root's
235 // base version to a value other than CHANGES_VERSION).
236 // This does nothing if the root's base version is already other than
237 // CHANGES_VERSION.
238 if (IsTypeWithClientGeneratedRoot(type_)) {
239 syncable::ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir_);
240 dir_->MarkInitialSyncEndedForType(&trans, type_);
241 }
242 }
243
244 bool DirectoryUpdateHandler::IsApplyUpdatesRequired() {
245 if (IsControlType(type_)) {
246 return false; // We don't process control types here.
247 }
248
249 return dir_->TypeHasUnappliedUpdates(type_);
250 }
251
252 void DirectoryUpdateHandler::UpdateSyncEntities(
253 syncable::ModelNeutralWriteTransaction* trans,
254 const SyncEntityList& applicable_updates,
255 sessions::StatusController* status) {
256 UpdateCounters* counters = debug_info_emitter_->GetMutableUpdateCounters();
257 counters->num_updates_received += applicable_updates.size();
258 ProcessDownloadedUpdates(dir_, trans, type_,
259 applicable_updates, status, counters);
260 }
261
262 bool DirectoryUpdateHandler::IsValidProgressMarker(
263 const sync_pb::DataTypeProgressMarker& progress_marker) const {
264 if (progress_marker.token().empty()) {
265 return false;
266 }
267 int field_number = progress_marker.data_type_id();
268 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number);
269 if (!IsRealDataType(model_type) || type_ != model_type) {
270 NOTREACHED()
271 << "Update handler of type " << ModelTypeToString(type_)
272 << " asked to process progress marker with invalid type "
273 << field_number;
274 return false;
275 }
276 return true;
277 }
278
279 void DirectoryUpdateHandler::UpdateProgressMarker(
280 const sync_pb::DataTypeProgressMarker& progress_marker) {
281 if (progress_marker.has_gc_directive() || !cached_gc_directive_) {
282 dir_->SetDownloadProgress(type_, progress_marker);
283 } else {
284 sync_pb::DataTypeProgressMarker merged_marker = progress_marker;
285 merged_marker.mutable_gc_directive()->CopyFrom(*cached_gc_directive_);
286 dir_->SetDownloadProgress(type_, merged_marker);
287 }
288 }
289
290 void DirectoryUpdateHandler::ExpireEntriesIfNeeded(
291 syncable::ModelNeutralWriteTransaction* trans,
292 const sync_pb::DataTypeProgressMarker& progress_marker) {
293 if (!cached_gc_directive_) {
294 sync_pb::DataTypeProgressMarker current_marker;
295 GetDownloadProgress(&current_marker);
296 if (current_marker.has_gc_directive()) {
297 cached_gc_directive_.reset(new sync_pb::GarbageCollectionDirective(
298 current_marker.gc_directive()));
299 }
300 }
301
302 if (!progress_marker.has_gc_directive())
303 return;
304
305 const sync_pb::GarbageCollectionDirective& new_gc_directive =
306 progress_marker.gc_directive();
307
308 if (new_gc_directive.has_version_watermark() &&
309 (!cached_gc_directive_ ||
310 cached_gc_directive_->version_watermark() <
311 new_gc_directive.version_watermark())) {
312 ExpireEntriesByVersion(dir_, trans, type_,
313 new_gc_directive.version_watermark());
314 }
315
316 cached_gc_directive_.reset(
317 new sync_pb::GarbageCollectionDirective(new_gc_directive));
318 }
319
320 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/directory_update_handler.h ('k') | sync/engine/directory_update_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698