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

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

Issue 11091009: sync: Merge {Verify,Process}UpdatesCommand (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Amend comment 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
« no previous file with comments | « sync/engine/verify_updates_command.h ('k') | sync/engine/verify_updates_command_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "sync/engine/verify_updates_command.h"
6
7 #include <string>
8
9 #include "base/location.h"
10 #include "sync/engine/syncer.h"
11 #include "sync/engine/syncer_proto_util.h"
12 #include "sync/engine/syncer_types.h"
13 #include "sync/engine/syncer_util.h"
14 #include "sync/internal_api/public/engine/model_safe_worker.h"
15 #include "sync/protocol/bookmark_specifics.pb.h"
16 #include "sync/protocol/sync.pb.h"
17 #include "sync/syncable/entry.h"
18 #include "sync/syncable/mutable_entry.h"
19 #include "sync/syncable/syncable_proto_util.h"
20 #include "sync/syncable/write_transaction.h"
21
22 namespace syncer {
23
24 using syncable::GET_BY_ID;
25 using syncable::SYNCER;
26 using syncable::WriteTransaction;
27
28 namespace {
29
30 // This function attempts to determine whether or not this update is genuinely
31 // new, or if it is a reflection of one of our own commits.
32 //
33 // There is a known inaccuracy in its implementation. If this update ends up
34 // being applied to a local item with a different ID, we will count the change
35 // as being a non-reflection update. Fortunately, the server usually updates
36 // our IDs correctly in its commit response, so a new ID during GetUpdate should
37 // be rare.
38 //
39 // The only secnarios I can think of where this might happen are:
40 // - We commit a new item to the server, but we don't persist the
41 // server-returned new ID to the database before we shut down. On the GetUpdate
42 // following the next restart, we will receive an update from the server that
43 // updates its local ID.
44 // - When two attempts to create an item with identical UNIQUE_CLIENT_TAG values
45 // collide at the server. I have seen this in testing. When it happens, the
46 // test server will send one of the clients a response to upate its local ID so
47 // that both clients will refer to the item using the same ID going forward. In
48 // this case, we're right to assume that the update is not a reflection.
49 //
50 // For more information, see FindLocalIdToUpdate().
51 bool UpdateContainsNewVersion(syncable::BaseTransaction *trans,
52 const sync_pb::SyncEntity &update) {
53 int64 existing_version = -1; // The server always sends positive versions.
54 syncable::Entry existing_entry(trans, GET_BY_ID,
55 SyncableIdFromProto(update.id_string()));
56 if (existing_entry.good())
57 existing_version = existing_entry.Get(syncable::BASE_VERSION);
58
59 if (!existing_entry.good() && update.deleted()) {
60 // There are several possible explanations for this. The most common cases
61 // will be first time sync and the redelivery of deletions we've already
62 // synced, accepted, and purged from our database. In either case, the
63 // update is useless to us. Let's count them all as "not new", even though
64 // that may not always be entirely accurate.
65 return false;
66 }
67
68 if (existing_entry.good() &&
69 !existing_entry.Get(syncable::UNIQUE_CLIENT_TAG).empty() &&
70 existing_entry.Get(syncable::IS_DEL) &&
71 update.deleted()) {
72 // Unique client tags will have their version set to zero when they're
73 // deleted. The usual version comparison logic won't be able to detect
74 // reflections of these items. Instead, we assume any received tombstones
75 // are reflections. That should be correct most of the time.
76 return false;
77 }
78
79 return existing_version < update.version();
80 }
81
82 // In the event that IDs match, but tags differ AttemptReuniteClient tag
83 // will have refused to unify the update.
84 // We should not attempt to apply it at all since it violates consistency
85 // rules.
86 VerifyResult VerifyTagConsistency(const sync_pb::SyncEntity& entry,
87 const syncable::MutableEntry& same_id) {
88 if (entry.has_client_defined_unique_tag() &&
89 entry.client_defined_unique_tag() !=
90 same_id.Get(syncable::UNIQUE_CLIENT_TAG)) {
91 return VERIFY_FAIL;
92 }
93 return VERIFY_UNDECIDED;
94 }
95 } // namespace
96
97 VerifyUpdatesCommand::VerifyUpdatesCommand() {}
98 VerifyUpdatesCommand::~VerifyUpdatesCommand() {}
99
100 std::set<ModelSafeGroup> VerifyUpdatesCommand::GetGroupsToChange(
101 const sessions::SyncSession& session) const {
102 std::set<ModelSafeGroup> groups_with_updates;
103
104 const sync_pb::GetUpdatesResponse& updates =
105 session.status_controller().updates_response().get_updates();
106 for (int i = 0; i < updates.entries().size(); i++) {
107 groups_with_updates.insert(
108 GetGroupForModelType(GetModelType(updates.entries(i)),
109 session.routing_info()));
110 }
111
112 return groups_with_updates;
113 }
114
115 SyncerError VerifyUpdatesCommand::ModelChangingExecuteImpl(
116 sessions::SyncSession* session) {
117 DVLOG(1) << "Beginning Update Verification";
118 syncable::Directory* dir = session->context()->directory();
119 WriteTransaction trans(FROM_HERE, SYNCER, dir);
120 sessions::StatusController* status = session->mutable_status_controller();
121 const sync_pb::GetUpdatesResponse& updates =
122 status->updates_response().get_updates();
123 int update_count = updates.entries().size();
124
125 ModelTypeSet requested_types = GetRoutingInfoTypes(
126 session->routing_info());
127
128 DVLOG(1) << update_count << " entries to verify";
129 for (int i = 0; i < update_count; i++) {
130 const sync_pb::SyncEntity& update = updates.entries(i);
131 ModelSafeGroup g = GetGroupForModelType(GetModelType(update),
132 session->routing_info());
133 if (g != status->group_restriction())
134 continue;
135
136 VerifyUpdateResult result = VerifyUpdate(&trans, update,
137 requested_types,
138 session->routing_info());
139 status->mutable_update_progress()->AddVerifyResult(result.value, update);
140 status->increment_num_updates_downloaded_by(1);
141 if (!UpdateContainsNewVersion(&trans, update))
142 status->increment_num_reflected_updates_downloaded_by(1);
143 if (update.deleted())
144 status->increment_num_tombstone_updates_downloaded_by(1);
145 }
146
147 return SYNCER_OK;
148 }
149
150 VerifyUpdatesCommand::VerifyUpdateResult VerifyUpdatesCommand::VerifyUpdate(
151 syncable::WriteTransaction* trans, const sync_pb::SyncEntity& entry,
152 ModelTypeSet requested_types,
153 const ModelSafeRoutingInfo& routes) {
154 syncable::Id id = SyncableIdFromProto(entry.id_string());
155 VerifyUpdateResult result = {VERIFY_FAIL, GROUP_PASSIVE};
156
157 const bool deleted = entry.has_deleted() && entry.deleted();
158 const bool is_directory = IsFolder(entry);
159 const ModelType model_type = GetModelType(entry);
160
161 if (!id.ServerKnows()) {
162 LOG(ERROR) << "Illegal negative id in received updates";
163 return result;
164 }
165 {
166 const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry);
167 if (name.empty() && !deleted) {
168 LOG(ERROR) << "Zero length name in non-deleted update";
169 return result;
170 }
171 }
172
173 syncable::MutableEntry same_id(trans, GET_BY_ID, id);
174 result.value = VerifyNewEntry(entry, &same_id, deleted);
175
176 ModelType placement_type = !deleted ? GetModelType(entry)
177 : same_id.good() ? same_id.GetModelType() : UNSPECIFIED;
178 result.placement = GetGroupForModelType(placement_type, routes);
179
180 if (VERIFY_UNDECIDED == result.value) {
181 result.value = VerifyTagConsistency(entry, same_id);
182 }
183
184 if (VERIFY_UNDECIDED == result.value) {
185 if (deleted) {
186 // For deletes the server could send tombostones for items that
187 // the client did not request. If so ignore those items.
188 if (IsRealDataType(placement_type) &&
189 !requested_types.Has(placement_type)) {
190 result.value = VERIFY_SKIP;
191 } else {
192 result.value = VERIFY_SUCCESS;
193 }
194 }
195 }
196
197 // If we have an existing entry, we check here for updates that break
198 // consistency rules.
199 if (VERIFY_UNDECIDED == result.value) {
200 result.value = VerifyUpdateConsistency(trans, entry, &same_id,
201 deleted, is_directory, model_type);
202 }
203
204 if (VERIFY_UNDECIDED == result.value)
205 result.value = VERIFY_SUCCESS; // No news is good news.
206
207 return result; // This might be VERIFY_SUCCESS as well
208 }
209
210 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/verify_updates_command.h ('k') | sync/engine/verify_updates_command_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698