Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / chrome / browser / sync / glue / generic_change_processor.cc
blob6c5f5e2935c363baa6f851ea4b8cf15fed852b52
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 "chrome/browser/sync/glue/generic_change_processor.h"
7 #include "base/location.h"
8 #include "base/string_number_conversions.h"
9 #include "base/utf_string_conversions.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "sync/api/sync_change.h"
12 #include "sync/api/sync_error.h"
13 #include "sync/api/syncable_service.h"
14 #include "sync/internal_api/public/base_node.h"
15 #include "sync/internal_api/public/change_record.h"
16 #include "sync/internal_api/public/read_node.h"
17 #include "sync/internal_api/public/read_transaction.h"
18 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
19 #include "sync/internal_api/public/write_node.h"
20 #include "sync/internal_api/public/write_transaction.h"
21 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
23 using content::BrowserThread;
25 namespace browser_sync {
27 GenericChangeProcessor::GenericChangeProcessor(
28 DataTypeErrorHandler* error_handler,
29 const base::WeakPtr<syncer::SyncableService>& local_service,
30 syncer::UserShare* user_share)
31 : ChangeProcessor(error_handler),
32 local_service_(local_service),
33 share_handle_(user_share) {
34 DCHECK(CalledOnValidThread());
37 GenericChangeProcessor::~GenericChangeProcessor() {
38 DCHECK(CalledOnValidThread());
41 void GenericChangeProcessor::ApplyChangesFromSyncModel(
42 const syncer::BaseTransaction* trans,
43 int64 model_version,
44 const syncer::ImmutableChangeRecordList& changes) {
45 DCHECK(CalledOnValidThread());
46 DCHECK(syncer_changes_.empty());
47 for (syncer::ChangeRecordList::const_iterator it =
48 changes.Get().begin(); it != changes.Get().end(); ++it) {
49 if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
50 syncer_changes_.push_back(
51 syncer::SyncChange(
52 FROM_HERE,
53 syncer::SyncChange::ACTION_DELETE,
54 syncer::SyncData::CreateRemoteData(it->id, it->specifics)));
55 } else {
56 syncer::SyncChange::SyncChangeType action =
57 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
58 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
59 // Need to load specifics from node.
60 syncer::ReadNode read_node(trans);
61 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
62 error_handler()->OnSingleDatatypeUnrecoverableError(
63 FROM_HERE,
64 "Failed to look up data for received change with id " +
65 base::Int64ToString(it->id));
66 return;
68 syncer_changes_.push_back(
69 syncer::SyncChange(
70 FROM_HERE,
71 action,
72 syncer::SyncData::CreateRemoteData(
73 it->id, read_node.GetEntitySpecifics())));
78 void GenericChangeProcessor::CommitChangesFromSyncModel() {
79 DCHECK(CalledOnValidThread());
80 if (syncer_changes_.empty())
81 return;
82 if (!local_service_) {
83 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
84 syncer::SyncError error(FROM_HERE, "Local service destroyed.", type);
85 error_handler()->OnSingleDatatypeUnrecoverableError(error.location(),
86 error.message());
87 return;
89 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
90 syncer_changes_);
91 syncer_changes_.clear();
92 if (error.IsSet()) {
93 error_handler()->OnSingleDatatypeUnrecoverableError(
94 error.location(), error.message());
98 syncer::SyncError GenericChangeProcessor::GetSyncDataForType(
99 syncer::ModelType type,
100 syncer::SyncDataList* current_sync_data) {
101 DCHECK(CalledOnValidThread());
102 std::string type_name = syncer::ModelTypeToString(type);
103 syncer::ReadTransaction trans(FROM_HERE, share_handle());
104 syncer::ReadNode root(&trans);
105 if (root.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
106 syncer::BaseNode::INIT_OK) {
107 syncer::SyncError error(FROM_HERE,
108 "Server did not create the top-level " + type_name +
109 " node. We might be running against an out-of-date server.",
110 type);
111 return error;
114 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
115 DCHECK_NE(type, syncer::BOOKMARKS);
117 int64 sync_child_id = root.GetFirstChildId();
118 while (sync_child_id != syncer::kInvalidId) {
119 syncer::ReadNode sync_child_node(&trans);
120 if (sync_child_node.InitByIdLookup(sync_child_id) !=
121 syncer::BaseNode::INIT_OK) {
122 syncer::SyncError error(FROM_HERE,
123 "Failed to fetch child node for type " + type_name + ".",
124 type);
125 return error;
127 current_sync_data->push_back(syncer::SyncData::CreateRemoteData(
128 sync_child_node.GetId(), sync_child_node.GetEntitySpecifics()));
129 sync_child_id = sync_child_node.GetSuccessorId();
131 return syncer::SyncError();
134 namespace {
136 // TODO(isherman): Investigating http://crbug.com/121592
137 // WARNING: this code is sensitive to compiler optimizations. Be careful
138 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
139 // the compiler attempts to merge it with other calls, losing useful information
140 // in breakpad uploads.
141 syncer::SyncError LogLookupFailure(
142 syncer::BaseNode::InitByLookupResult lookup_result,
143 const tracked_objects::Location& from_here,
144 const std::string& error_prefix,
145 syncer::ModelType type,
146 DataTypeErrorHandler* error_handler) {
147 switch (lookup_result) {
148 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
149 syncer::SyncError error;
150 error.Reset(from_here,
151 error_prefix +
152 "could not find entry matching the lookup criteria.",
153 type);
154 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
155 error.message());
156 LOG(ERROR) << "Delete: Bad entry.";
157 return error;
159 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
160 syncer::SyncError error;
161 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
162 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
163 error.message());
164 LOG(ERROR) << "Delete: Deleted entry.";
165 return error;
167 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
168 syncer::SyncError error;
169 error.Reset(from_here, error_prefix + "unable to decrypt", type);
170 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
171 error.message());
172 LOG(ERROR) << "Delete: Undecryptable entry.";
173 return error;
175 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
176 syncer::SyncError error;
177 error.Reset(from_here,
178 error_prefix + "a precondition was not met for calling init.",
179 type);
180 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
181 error.message());
182 LOG(ERROR) << "Delete: Failed precondition.";
183 return error;
185 default: {
186 syncer::SyncError error;
187 // Should have listed all the possible error cases above.
188 error.Reset(from_here, error_prefix + "unknown error", type);
189 error_handler->OnSingleDatatypeUnrecoverableError(FROM_HERE,
190 error.message());
191 LOG(ERROR) << "Delete: Unknown error.";
192 return error;
197 syncer::SyncError AttemptDelete(
198 const syncer::SyncChange& change,
199 syncer::ModelType type,
200 const std::string& type_str,
201 syncer::WriteNode* node,
202 DataTypeErrorHandler* error_handler) {
203 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
204 if (change.sync_data().IsLocal()) {
205 const std::string& tag = change.sync_data().GetTag();
206 if (tag.empty()) {
207 syncer::SyncError error(
208 FROM_HERE,
209 "Failed to delete " + type_str + " node. Local data, empty tag. " +
210 change.location().ToString(),
211 type);
212 error_handler->OnSingleDatatypeUnrecoverableError(error.location(),
213 error.message());
214 NOTREACHED();
215 return error;
218 syncer::BaseNode::InitByLookupResult result =
219 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
220 if (result != syncer::BaseNode::INIT_OK) {
221 return LogLookupFailure(
222 result, FROM_HERE,
223 "Failed to delete " + type_str + " node. Local data. " +
224 change.location().ToString(),
225 type, error_handler);
227 } else {
228 syncer::BaseNode::InitByLookupResult result =
229 node->InitByIdLookup(change.sync_data().GetRemoteId());
230 if (result != syncer::BaseNode::INIT_OK) {
231 return LogLookupFailure(
232 result, FROM_HERE,
233 "Failed to delete " + type_str + " node. Non-local data. " +
234 change.location().ToString(),
235 type, error_handler);
238 node->Remove();
239 return syncer::SyncError();
242 } // namespace
244 // WARNING: this code is sensitive to compiler optimizations. Be careful
245 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
246 // the compiler attempts to merge it with other calls, losing useful information
247 // in breakpad uploads.
248 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
249 const tracked_objects::Location& from_here,
250 const syncer::SyncChangeList& list_of_changes) {
251 DCHECK(CalledOnValidThread());
252 syncer::WriteTransaction trans(from_here, share_handle());
254 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
255 iter != list_of_changes.end();
256 ++iter) {
257 const syncer::SyncChange& change = *iter;
258 DCHECK_NE(change.sync_data().GetDataType(), syncer::UNSPECIFIED);
259 syncer::ModelType type = change.sync_data().GetDataType();
260 std::string type_str = syncer::ModelTypeToString(type);
261 syncer::WriteNode sync_node(&trans);
262 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
263 syncer::SyncError error =
264 AttemptDelete(change, type, type_str, &sync_node,
265 error_handler());
266 if (error.IsSet()) {
267 NOTREACHED();
268 return error;
270 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
271 // TODO(sync): Handle other types of creation (custom parents, folders,
272 // etc.).
273 syncer::ReadNode root_node(&trans);
274 if (root_node.InitByTagLookup(
275 syncer::ModelTypeToRootTag(change.sync_data().GetDataType())) !=
276 syncer::BaseNode::INIT_OK) {
277 syncer::SyncError error(FROM_HERE,
278 "Failed to look up root node for type " + type_str,
279 type);
280 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
281 error.message());
282 NOTREACHED();
283 LOG(ERROR) << "Create: no root node.";
284 return error;
286 syncer::WriteNode::InitUniqueByCreationResult result =
287 sync_node.InitUniqueByCreation(change.sync_data().GetDataType(),
288 root_node,
289 change.sync_data().GetTag());
290 if (result != syncer::WriteNode::INIT_SUCCESS) {
291 std::string error_prefix = "Failed to create " + type_str + " node: " +
292 change.location().ToString() + ", ";
293 switch (result) {
294 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: {
295 syncer::SyncError error;
296 error.Reset(FROM_HERE, error_prefix + "empty tag", type);
297 error_handler()->OnSingleDatatypeUnrecoverableError(
298 FROM_HERE, error.message());
299 LOG(ERROR) << "Create: Empty tag.";
300 return error;
302 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
303 syncer::SyncError error;
304 error.Reset(FROM_HERE, error_prefix + "entry already exists", type);
305 error_handler()->OnSingleDatatypeUnrecoverableError(
306 FROM_HERE, error.message());
307 LOG(ERROR) << "Create: Entry exists.";
308 return error;
310 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
311 syncer::SyncError error;
312 error.Reset(FROM_HERE, error_prefix + "failed to create entry",
313 type);
314 error_handler()->OnSingleDatatypeUnrecoverableError(
315 FROM_HERE, error.message());
316 LOG(ERROR) << "Create: Could not create entry.";
317 return error;
319 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
320 syncer::SyncError error;
321 error.Reset(FROM_HERE, error_prefix + "failed to set predecessor",
322 type);
323 error_handler()->OnSingleDatatypeUnrecoverableError(
324 FROM_HERE, error.message());
325 LOG(ERROR) << "Create: Bad predecessor.";
326 return error;
328 default: {
329 syncer::SyncError error;
330 error.Reset(FROM_HERE, error_prefix + "unknown error", type);
331 error_handler()->OnSingleDatatypeUnrecoverableError(
332 FROM_HERE, error.message());
333 LOG(ERROR) << "Create: Unknown error.";
334 return error;
338 sync_node.SetTitle(UTF8ToWide(change.sync_data().GetTitle()));
339 sync_node.SetEntitySpecifics(change.sync_data().GetSpecifics());
340 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
341 // TODO(zea): consider having this logic for all possible changes?
342 syncer::BaseNode::InitByLookupResult result =
343 sync_node.InitByClientTagLookup(change.sync_data().GetDataType(),
344 change.sync_data().GetTag());
345 if (result != syncer::BaseNode::INIT_OK) {
346 std::string error_prefix = "Failed to load " + type_str + " node. " +
347 change.location().ToString() + ", ";
348 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
349 syncer::SyncError error;
350 error.Reset(FROM_HERE,
351 error_prefix + "empty tag",
352 type);
353 error_handler()->OnSingleDatatypeUnrecoverableError(
354 FROM_HERE, error.message());
355 LOG(ERROR) << "Update: Empty tag.";
356 return error;
357 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
358 syncer::SyncError error;
359 error.Reset(FROM_HERE,
360 error_prefix + "bad entry",
361 type);
362 error_handler()->OnSingleDatatypeUnrecoverableError(
363 FROM_HERE, error.message());
364 LOG(ERROR) << "Update: bad entry.";
365 return error;
366 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
367 syncer::SyncError error;
368 error.Reset(FROM_HERE,
369 error_prefix + "deleted entry",
370 type);
371 error_handler()->OnSingleDatatypeUnrecoverableError(
372 FROM_HERE, error.message());
373 LOG(ERROR) << "Update: deleted entry.";
374 return error;
375 } else {
376 syncer::Cryptographer* crypto = trans.GetCryptographer();
377 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
378 const sync_pb::EntitySpecifics& specifics =
379 sync_node.GetEntry()->Get(syncer::syncable::SPECIFICS);
380 CHECK(specifics.has_encrypted());
381 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
382 const bool agreement = encrypted_types.Has(type);
383 if (!agreement && !can_decrypt) {
384 syncer::SyncError error;
385 error.Reset(FROM_HERE,
386 "Failed to load encrypted entry, missing key and "
387 "nigori mismatch for " + type_str + ".",
388 type);
389 error_handler()->OnSingleDatatypeUnrecoverableError(
390 FROM_HERE, error.message());
391 LOG(ERROR) << "Update: encr case 1.";
392 return error;
393 } else if (agreement && can_decrypt) {
394 syncer::SyncError error;
395 error.Reset(FROM_HERE,
396 "Failed to load encrypted entry, we have the key "
397 "and the nigori matches (?!) for " + type_str + ".",
398 type);
399 error_handler()->OnSingleDatatypeUnrecoverableError(
400 FROM_HERE, error.message());
401 LOG(ERROR) << "Update: encr case 2.";
402 return error;
403 } else if (agreement) {
404 syncer::SyncError error;
405 error.Reset(FROM_HERE,
406 "Failed to load encrypted entry, missing key and "
407 "the nigori matches for " + type_str + ".",
408 type);
409 error_handler()->OnSingleDatatypeUnrecoverableError(
410 FROM_HERE, error.message());
411 LOG(ERROR) << "Update: encr case 3.";
412 return error;
413 } else {
414 syncer::SyncError error;
415 error.Reset(FROM_HERE,
416 "Failed to load encrypted entry, we have the key"
417 "(?!) and nigori mismatch for " + type_str + ".",
418 type);
419 error_handler()->OnSingleDatatypeUnrecoverableError(
420 FROM_HERE, error.message());
421 LOG(ERROR) << "Update: encr case 4.";
422 return error;
425 } else {
426 sync_node.SetTitle(UTF8ToWide(change.sync_data().GetTitle()));
427 sync_node.SetEntitySpecifics(change.sync_data().GetSpecifics());
428 // TODO(sync): Support updating other parts of the sync node (title,
429 // successor, parent, etc.).
431 } else {
432 syncer::SyncError error(
433 FROM_HERE,
434 "Received unset SyncChange in the change processor, " +
435 change.location().ToString(),
436 type);
437 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE,
438 error.message());
439 NOTREACHED();
440 LOG(ERROR) << "Unset sync change.";
441 return error;
444 return syncer::SyncError();
447 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
448 syncer::ModelType type,
449 bool* has_nodes) {
450 DCHECK(CalledOnValidThread());
451 DCHECK(has_nodes);
452 DCHECK_NE(type, syncer::UNSPECIFIED);
453 std::string type_name = syncer::ModelTypeToString(type);
454 std::string err_str = "Server did not create the top-level " + type_name +
455 " node. We might be running against an out-of-date server.";
456 *has_nodes = false;
457 syncer::ReadTransaction trans(FROM_HERE, share_handle());
458 syncer::ReadNode type_root_node(&trans);
459 if (type_root_node.InitByTagLookup(syncer::ModelTypeToRootTag(type)) !=
460 syncer::BaseNode::INIT_OK) {
461 LOG(ERROR) << err_str;
462 return false;
465 // The sync model has user created nodes if the type's root node has any
466 // children.
467 *has_nodes = type_root_node.HasChildren();
468 return true;
471 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type) {
472 DCHECK(CalledOnValidThread());
473 DCHECK_NE(type, syncer::UNSPECIFIED);
474 // We only access the cryptographer while holding a transaction.
475 syncer::ReadTransaction trans(FROM_HERE, share_handle());
476 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
477 return !encrypted_types.Has(type) ||
478 trans.GetCryptographer()->is_ready();
481 void GenericChangeProcessor::StartImpl(Profile* profile) {
482 DCHECK(CalledOnValidThread());
485 syncer::UserShare* GenericChangeProcessor::share_handle() const {
486 DCHECK(CalledOnValidThread());
487 return share_handle_;
490 } // namespace browser_sync