Add abhijeet.k@samsung.com to AUTHORS list.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor.cc
blob3a1f19f7b326453a1367020f31d694e995cab193
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.
5 #include "components/sync_driver/generic_change_processor.h"
7 #include "base/location.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/sync_driver/sync_api_component_factory.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 namespace sync_driver {
25 namespace {
27 const int kContextSizeLimit = 1024; // Datatype context size limit.
29 void SetNodeSpecifics(const sync_pb::EntitySpecifics& entity_specifics,
30 syncer::WriteNode* write_node) {
31 if (syncer::GetModelTypeFromSpecifics(entity_specifics) ==
32 syncer::PASSWORDS) {
33 write_node->SetPasswordSpecifics(
34 entity_specifics.password().client_only_encrypted_data());
35 } else {
36 write_node->SetEntitySpecifics(entity_specifics);
40 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
41 sync_pb::AttachmentMetadataRecord AttachmentIdToRecord(
42 const syncer::AttachmentId& attachment_id) {
43 sync_pb::AttachmentMetadataRecord record;
44 *record.mutable_id() = attachment_id.GetProto();
45 return record;
48 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
49 void SetAttachmentMetadata(const syncer::AttachmentIdList& attachment_ids,
50 syncer::WriteNode* write_node) {
51 DCHECK(write_node);
52 sync_pb::AttachmentMetadata attachment_metadata;
53 std::transform(
54 attachment_ids.begin(),
55 attachment_ids.end(),
56 RepeatedFieldBackInserter(attachment_metadata.mutable_record()),
57 AttachmentIdToRecord);
58 write_node->SetAttachmentMetadata(attachment_metadata);
61 syncer::SyncData BuildRemoteSyncData(
62 int64 sync_id,
63 const syncer::BaseNode& read_node,
64 const syncer::AttachmentServiceProxy& attachment_service_proxy) {
65 const syncer::AttachmentIdList& attachment_ids = read_node.GetAttachmentIds();
66 // Use the specifics of non-password datatypes directly (encryption has
67 // already been handled).
68 if (read_node.GetModelType() != syncer::PASSWORDS) {
69 return syncer::SyncData::CreateRemoteData(sync_id,
70 read_node.GetEntitySpecifics(),
71 read_node.GetModificationTime(),
72 attachment_ids,
73 attachment_service_proxy);
76 // Passwords must be accessed differently, to account for their encryption,
77 // and stored into a temporary EntitySpecifics.
78 sync_pb::EntitySpecifics password_holder;
79 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
80 CopyFrom(read_node.GetPasswordSpecifics());
81 return syncer::SyncData::CreateRemoteData(sync_id,
82 password_holder,
83 read_node.GetModificationTime(),
84 attachment_ids,
85 attachment_service_proxy);
88 } // namespace
90 GenericChangeProcessor::GenericChangeProcessor(
91 syncer::ModelType type,
92 DataTypeErrorHandler* error_handler,
93 const base::WeakPtr<syncer::SyncableService>& local_service,
94 const base::WeakPtr<syncer::SyncMergeResult>& merge_result,
95 syncer::UserShare* user_share,
96 SyncApiComponentFactory* sync_factory,
97 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store)
98 : ChangeProcessor(error_handler),
99 type_(type),
100 local_service_(local_service),
101 merge_result_(merge_result),
102 share_handle_(user_share),
103 weak_ptr_factory_(this) {
104 DCHECK(CalledOnValidThread());
105 DCHECK_NE(type_, syncer::UNSPECIFIED);
106 if (attachment_store) {
107 std::string store_birthday;
109 syncer::ReadTransaction trans(FROM_HERE, share_handle());
110 store_birthday = trans.GetStoreBirthday();
112 attachment_service_ = sync_factory->CreateAttachmentService(
113 attachment_store.Pass(), *user_share, store_birthday, type, this);
114 attachment_service_weak_ptr_factory_.reset(
115 new base::WeakPtrFactory<syncer::AttachmentService>(
116 attachment_service_.get()));
117 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
118 base::MessageLoopProxy::current(),
119 attachment_service_weak_ptr_factory_->GetWeakPtr());
120 UploadAllAttachmentsNotOnServer();
121 } else {
122 attachment_service_proxy_ = syncer::AttachmentServiceProxy(
123 base::MessageLoopProxy::current(),
124 base::WeakPtr<syncer::AttachmentService>());
128 GenericChangeProcessor::~GenericChangeProcessor() {
129 DCHECK(CalledOnValidThread());
132 void GenericChangeProcessor::ApplyChangesFromSyncModel(
133 const syncer::BaseTransaction* trans,
134 int64 model_version,
135 const syncer::ImmutableChangeRecordList& changes) {
136 DCHECK(CalledOnValidThread());
137 DCHECK(syncer_changes_.empty());
138 for (syncer::ChangeRecordList::const_iterator it =
139 changes.Get().begin(); it != changes.Get().end(); ++it) {
140 if (it->action == syncer::ChangeRecord::ACTION_DELETE) {
141 scoped_ptr<sync_pb::EntitySpecifics> specifics;
142 if (it->specifics.has_password()) {
143 DCHECK(it->extra.get());
144 specifics.reset(new sync_pb::EntitySpecifics(it->specifics));
145 specifics->mutable_password()->mutable_client_only_encrypted_data()->
146 CopyFrom(it->extra->unencrypted());
148 const syncer::AttachmentIdList empty_list_of_attachment_ids;
149 syncer_changes_.push_back(syncer::SyncChange(
150 FROM_HERE, syncer::SyncChange::ACTION_DELETE,
151 syncer::SyncData::CreateRemoteData(
152 it->id, specifics ? *specifics : it->specifics, base::Time(),
153 empty_list_of_attachment_ids, attachment_service_proxy_)));
154 } else {
155 syncer::SyncChange::SyncChangeType action =
156 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
157 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
158 // Need to load specifics from node.
159 syncer::ReadNode read_node(trans);
160 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
161 syncer::SyncError error(
162 FROM_HERE,
163 syncer::SyncError::DATATYPE_ERROR,
164 "Failed to look up data for received change with id " +
165 base::Int64ToString(it->id),
166 syncer::GetModelTypeFromSpecifics(it->specifics));
167 error_handler()->OnSingleDataTypeUnrecoverableError(error);
168 return;
170 syncer_changes_.push_back(syncer::SyncChange(
171 FROM_HERE, action,
172 BuildRemoteSyncData(it->id, read_node, attachment_service_proxy_)));
177 void GenericChangeProcessor::CommitChangesFromSyncModel() {
178 DCHECK(CalledOnValidThread());
179 if (syncer_changes_.empty())
180 return;
181 if (!local_service_.get()) {
182 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
183 syncer::SyncError error(FROM_HERE,
184 syncer::SyncError::DATATYPE_ERROR,
185 "Local service destroyed.",
186 type);
187 error_handler()->OnSingleDataTypeUnrecoverableError(error);
188 return;
190 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
191 syncer_changes_);
192 syncer_changes_.clear();
193 if (error.IsSet())
194 error_handler()->OnSingleDataTypeUnrecoverableError(error);
197 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
198 syncer::ModelType type) const {
199 DCHECK_EQ(type_, type);
200 // This is slow / memory intensive. Should be used sparingly by datatypes.
201 syncer::SyncDataList data;
202 GetAllSyncDataReturnError(&data);
203 return data;
206 syncer::SyncError GenericChangeProcessor::UpdateDataTypeContext(
207 syncer::ModelType type,
208 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
209 const std::string& context) {
210 DCHECK(syncer::ProtocolTypes().Has(type));
211 DCHECK_EQ(type_, type);
213 if (context.size() > static_cast<size_t>(kContextSizeLimit)) {
214 return syncer::SyncError(FROM_HERE,
215 syncer::SyncError::DATATYPE_ERROR,
216 "Context size limit exceeded.",
217 type);
220 syncer::WriteTransaction trans(FROM_HERE, share_handle());
221 trans.SetDataTypeContext(type, refresh_status, context);
223 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
224 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
226 return syncer::SyncError();
229 void GenericChangeProcessor::OnAttachmentUploaded(
230 const syncer::AttachmentId& attachment_id) {
231 syncer::WriteTransaction trans(FROM_HERE, share_handle());
232 trans.UpdateEntriesMarkAttachmentAsOnServer(attachment_id);
235 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
236 syncer::SyncDataList* current_sync_data) const {
237 DCHECK(CalledOnValidThread());
238 std::string type_name = syncer::ModelTypeToString(type_);
239 syncer::ReadTransaction trans(FROM_HERE, share_handle());
240 syncer::ReadNode root(&trans);
241 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
242 syncer::SyncError error(FROM_HERE,
243 syncer::SyncError::DATATYPE_ERROR,
244 "Server did not create the top-level " + type_name +
245 " node. We might be running against an out-of-"
246 "date server.",
247 type_);
248 return error;
251 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
252 DCHECK_NE(type_, syncer::BOOKMARKS);
254 std::vector<int64> child_ids;
255 root.GetChildIds(&child_ids);
257 for (std::vector<int64>::iterator it = child_ids.begin();
258 it != child_ids.end(); ++it) {
259 syncer::ReadNode sync_child_node(&trans);
260 if (sync_child_node.InitByIdLookup(*it) !=
261 syncer::BaseNode::INIT_OK) {
262 syncer::SyncError error(
263 FROM_HERE,
264 syncer::SyncError::DATATYPE_ERROR,
265 "Failed to fetch child node for type " + type_name + ".",
266 type_);
267 return error;
269 current_sync_data->push_back(BuildRemoteSyncData(
270 sync_child_node.GetId(), sync_child_node, attachment_service_proxy_));
272 return syncer::SyncError();
275 bool GenericChangeProcessor::GetDataTypeContext(std::string* context) const {
276 syncer::ReadTransaction trans(FROM_HERE, share_handle());
277 sync_pb::DataTypeContext context_proto;
278 trans.GetDataTypeContext(type_, &context_proto);
279 if (!context_proto.has_context())
280 return false;
282 DCHECK_EQ(type_,
283 syncer::GetModelTypeFromSpecificsFieldNumber(
284 context_proto.data_type_id()));
285 *context = context_proto.context();
286 return true;
289 int GenericChangeProcessor::GetSyncCount() {
290 syncer::ReadTransaction trans(FROM_HERE, share_handle());
291 syncer::ReadNode root(&trans);
292 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK)
293 return 0;
295 // Subtract one to account for type's root node.
296 return root.GetTotalNodeCount() - 1;
299 namespace {
301 // WARNING: this code is sensitive to compiler optimizations. Be careful
302 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
303 // the compiler attempts to merge it with other calls, losing useful information
304 // in breakpad uploads.
305 syncer::SyncError LogLookupFailure(
306 syncer::BaseNode::InitByLookupResult lookup_result,
307 const tracked_objects::Location& from_here,
308 const std::string& error_prefix,
309 syncer::ModelType type,
310 DataTypeErrorHandler* error_handler) {
311 switch (lookup_result) {
312 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
313 syncer::SyncError error;
314 error.Reset(from_here,
315 error_prefix +
316 "could not find entry matching the lookup criteria.",
317 type);
318 error_handler->OnSingleDataTypeUnrecoverableError(error);
319 LOG(ERROR) << "Delete: Bad entry.";
320 return error;
322 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
323 syncer::SyncError error;
324 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
325 error_handler->OnSingleDataTypeUnrecoverableError(error);
326 LOG(ERROR) << "Delete: Deleted entry.";
327 return error;
329 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
330 syncer::SyncError error;
331 error.Reset(from_here, error_prefix + "unable to decrypt", type);
332 error_handler->OnSingleDataTypeUnrecoverableError(error);
333 LOG(ERROR) << "Delete: Undecryptable entry.";
334 return error;
336 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
337 syncer::SyncError error;
338 error.Reset(from_here,
339 error_prefix + "a precondition was not met for calling init.",
340 type);
341 error_handler->OnSingleDataTypeUnrecoverableError(error);
342 LOG(ERROR) << "Delete: Failed precondition.";
343 return error;
345 default: {
346 syncer::SyncError error;
347 // Should have listed all the possible error cases above.
348 error.Reset(from_here, error_prefix + "unknown error", type);
349 error_handler->OnSingleDataTypeUnrecoverableError(error);
350 LOG(ERROR) << "Delete: Unknown error.";
351 return error;
356 syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
357 syncer::ModelType type,
358 const std::string& type_str,
359 syncer::WriteNode* node,
360 DataTypeErrorHandler* error_handler) {
361 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
362 if (change.sync_data().IsLocal()) {
363 const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
364 if (tag.empty()) {
365 syncer::SyncError error(
366 FROM_HERE,
367 syncer::SyncError::DATATYPE_ERROR,
368 "Failed to delete " + type_str + " node. Local data, empty tag. " +
369 change.location().ToString(),
370 type);
371 error_handler->OnSingleDataTypeUnrecoverableError(error);
372 NOTREACHED();
373 return error;
376 syncer::BaseNode::InitByLookupResult result =
377 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
378 if (result != syncer::BaseNode::INIT_OK) {
379 return LogLookupFailure(
380 result, FROM_HERE,
381 "Failed to delete " + type_str + " node. Local data. " +
382 change.location().ToString(),
383 type, error_handler);
385 } else {
386 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup(
387 syncer::SyncDataRemote(change.sync_data()).GetId());
388 if (result != syncer::BaseNode::INIT_OK) {
389 return LogLookupFailure(
390 result, FROM_HERE,
391 "Failed to delete " + type_str + " node. Non-local data. " +
392 change.location().ToString(),
393 type, error_handler);
396 if (IsActOnceDataType(type))
397 node->Drop();
398 else
399 node->Tombstone();
400 return syncer::SyncError();
403 } // namespace
405 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
406 const tracked_objects::Location& from_here,
407 const syncer::SyncChangeList& list_of_changes) {
408 DCHECK(CalledOnValidThread());
410 // Keep track of brand new attachments so we can persist them on this device
411 // and upload them to the server.
412 syncer::AttachmentIdSet new_attachments;
414 syncer::WriteTransaction trans(from_here, share_handle());
416 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
417 iter != list_of_changes.end();
418 ++iter) {
419 const syncer::SyncChange& change = *iter;
420 DCHECK_EQ(change.sync_data().GetDataType(), type_);
421 std::string type_str = syncer::ModelTypeToString(type_);
422 syncer::WriteNode sync_node(&trans);
423 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
424 syncer::SyncError error =
425 AttemptDelete(change, type_, type_str, &sync_node, error_handler());
426 if (error.IsSet()) {
427 NOTREACHED();
428 return error;
430 if (merge_result_.get()) {
431 merge_result_->set_num_items_deleted(
432 merge_result_->num_items_deleted() + 1);
434 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
435 syncer::SyncError error = HandleActionAdd(
436 change, type_str, trans, &sync_node, &new_attachments);
437 if (error.IsSet()) {
438 return error;
440 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
441 syncer::SyncError error = HandleActionUpdate(
442 change, type_str, trans, &sync_node, &new_attachments);
443 if (error.IsSet()) {
444 return error;
446 } else {
447 syncer::SyncError error(
448 FROM_HERE,
449 syncer::SyncError::DATATYPE_ERROR,
450 "Received unset SyncChange in the change processor, " +
451 change.location().ToString(),
452 type_);
453 error_handler()->OnSingleDataTypeUnrecoverableError(error);
454 NOTREACHED();
455 LOG(ERROR) << "Unset sync change.";
456 return error;
460 if (!new_attachments.empty()) {
461 // If datatype uses attachments it should have supplied attachment store
462 // which would initialize attachment_service_. Fail if it isn't so.
463 if (!attachment_service_.get()) {
464 syncer::SyncError error(
465 FROM_HERE,
466 syncer::SyncError::DATATYPE_ERROR,
467 "Datatype performs attachment operation without initializing "
468 "attachment store",
469 type_);
470 error_handler()->OnSingleDataTypeUnrecoverableError(error);
471 NOTREACHED();
472 return error;
474 syncer::AttachmentIdList ids_to_upload;
475 ids_to_upload.reserve(new_attachments.size());
476 std::copy(new_attachments.begin(), new_attachments.end(),
477 std::back_inserter(ids_to_upload));
478 attachment_service_->UploadAttachments(ids_to_upload);
481 return syncer::SyncError();
484 // WARNING: this code is sensitive to compiler optimizations. Be careful
485 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
486 // the compiler attempts to merge it with other calls, losing useful information
487 // in breakpad uploads.
488 syncer::SyncError GenericChangeProcessor::HandleActionAdd(
489 const syncer::SyncChange& change,
490 const std::string& type_str,
491 const syncer::WriteTransaction& trans,
492 syncer::WriteNode* sync_node,
493 syncer::AttachmentIdSet* new_attachments) {
494 // TODO(sync): Handle other types of creation (custom parents, folders,
495 // etc.).
496 syncer::ReadNode root_node(&trans);
497 const syncer::SyncDataLocal sync_data_local(change.sync_data());
498 if (root_node.InitTypeRoot(sync_data_local.GetDataType()) !=
499 syncer::BaseNode::INIT_OK) {
500 syncer::SyncError error(FROM_HERE,
501 syncer::SyncError::DATATYPE_ERROR,
502 "Failed to look up root node for type " + type_str,
503 type_);
504 error_handler()->OnSingleDataTypeUnrecoverableError(error);
505 NOTREACHED();
506 LOG(ERROR) << "Create: no root node.";
507 return error;
509 syncer::WriteNode::InitUniqueByCreationResult result =
510 sync_node->InitUniqueByCreation(
511 sync_data_local.GetDataType(), root_node, sync_data_local.GetTag());
512 if (result != syncer::WriteNode::INIT_SUCCESS) {
513 std::string error_prefix = "Failed to create " + type_str + " node: " +
514 change.location().ToString() + ", ";
515 switch (result) {
516 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG: {
517 syncer::SyncError error;
518 error.Reset(FROM_HERE, error_prefix + "empty tag", type_);
519 error_handler()->OnSingleDataTypeUnrecoverableError(error);
520 LOG(ERROR) << "Create: Empty tag.";
521 return error;
523 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
524 syncer::SyncError error;
525 error.Reset(FROM_HERE, error_prefix + "entry already exists", type_);
526 error_handler()->OnSingleDataTypeUnrecoverableError(error);
527 LOG(ERROR) << "Create: Entry exists.";
528 return error;
530 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
531 syncer::SyncError error;
532 error.Reset(FROM_HERE, error_prefix + "failed to create entry", type_);
533 error_handler()->OnSingleDataTypeUnrecoverableError(error);
534 LOG(ERROR) << "Create: Could not create entry.";
535 return error;
537 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
538 syncer::SyncError error;
539 error.Reset(
540 FROM_HERE, error_prefix + "failed to set predecessor", type_);
541 error_handler()->OnSingleDataTypeUnrecoverableError(error);
542 LOG(ERROR) << "Create: Bad predecessor.";
543 return error;
545 default: {
546 syncer::SyncError error;
547 error.Reset(FROM_HERE, error_prefix + "unknown error", type_);
548 error_handler()->OnSingleDataTypeUnrecoverableError(error);
549 LOG(ERROR) << "Create: Unknown error.";
550 return error;
554 sync_node->SetTitle(change.sync_data().GetTitle());
555 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
557 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
558 SetAttachmentMetadata(attachment_ids, sync_node);
560 // Return any newly added attachments.
561 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
562 if (merge_result_.get()) {
563 merge_result_->set_num_items_added(merge_result_->num_items_added() + 1);
565 return syncer::SyncError();
567 // WARNING: this code is sensitive to compiler optimizations. Be careful
568 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
569 // the compiler attempts to merge it with other calls, losing useful information
570 // in breakpad uploads.
571 syncer::SyncError GenericChangeProcessor::HandleActionUpdate(
572 const syncer::SyncChange& change,
573 const std::string& type_str,
574 const syncer::WriteTransaction& trans,
575 syncer::WriteNode* sync_node,
576 syncer::AttachmentIdSet* new_attachments) {
577 // TODO(zea): consider having this logic for all possible changes?
579 const syncer::SyncDataLocal sync_data_local(change.sync_data());
580 syncer::BaseNode::InitByLookupResult result =
581 sync_node->InitByClientTagLookup(sync_data_local.GetDataType(),
582 sync_data_local.GetTag());
583 if (result != syncer::BaseNode::INIT_OK) {
584 std::string error_prefix = "Failed to load " + type_str + " node. " +
585 change.location().ToString() + ", ";
586 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
587 syncer::SyncError error;
588 error.Reset(FROM_HERE, error_prefix + "empty tag", type_);
589 error_handler()->OnSingleDataTypeUnrecoverableError(error);
590 LOG(ERROR) << "Update: Empty tag.";
591 return error;
592 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
593 syncer::SyncError error;
594 error.Reset(FROM_HERE, error_prefix + "bad entry", type_);
595 error_handler()->OnSingleDataTypeUnrecoverableError(error);
596 LOG(ERROR) << "Update: bad entry.";
597 return error;
598 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
599 syncer::SyncError error;
600 error.Reset(FROM_HERE, error_prefix + "deleted entry", type_);
601 error_handler()->OnSingleDataTypeUnrecoverableError(error);
602 LOG(ERROR) << "Update: deleted entry.";
603 return error;
604 } else {
605 syncer::Cryptographer* crypto = trans.GetCryptographer();
606 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
607 const sync_pb::EntitySpecifics& specifics =
608 sync_node->GetEntry()->GetSpecifics();
609 CHECK(specifics.has_encrypted());
610 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
611 const bool agreement = encrypted_types.Has(type_);
612 if (!agreement && !can_decrypt) {
613 syncer::SyncError error;
614 error.Reset(FROM_HERE,
615 "Failed to load encrypted entry, missing key and "
616 "nigori mismatch for " +
617 type_str + ".",
618 type_);
619 error_handler()->OnSingleDataTypeUnrecoverableError(error);
620 LOG(ERROR) << "Update: encr case 1.";
621 return error;
622 } else if (agreement && can_decrypt) {
623 syncer::SyncError error;
624 error.Reset(FROM_HERE,
625 "Failed to load encrypted entry, we have the key "
626 "and the nigori matches (?!) for " +
627 type_str + ".",
628 type_);
629 error_handler()->OnSingleDataTypeUnrecoverableError(error);
630 LOG(ERROR) << "Update: encr case 2.";
631 return error;
632 } else if (agreement) {
633 syncer::SyncError error;
634 error.Reset(FROM_HERE,
635 "Failed to load encrypted entry, missing key and "
636 "the nigori matches for " +
637 type_str + ".",
638 type_);
639 error_handler()->OnSingleDataTypeUnrecoverableError(error);
640 LOG(ERROR) << "Update: encr case 3.";
641 return error;
642 } else {
643 syncer::SyncError error;
644 error.Reset(FROM_HERE,
645 "Failed to load encrypted entry, we have the key"
646 "(?!) and nigori mismatch for " +
647 type_str + ".",
648 type_);
649 error_handler()->OnSingleDataTypeUnrecoverableError(error);
650 LOG(ERROR) << "Update: encr case 4.";
651 return error;
656 sync_node->SetTitle(change.sync_data().GetTitle());
657 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
658 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
659 SetAttachmentMetadata(attachment_ids, sync_node);
661 // Return any newly added attachments.
662 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
664 if (merge_result_.get()) {
665 merge_result_->set_num_items_modified(merge_result_->num_items_modified() +
668 // TODO(sync): Support updating other parts of the sync node (title,
669 // successor, parent, etc.).
670 return syncer::SyncError();
673 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
674 DCHECK(CalledOnValidThread());
675 DCHECK(has_nodes);
676 std::string type_name = syncer::ModelTypeToString(type_);
677 std::string err_str = "Server did not create the top-level " + type_name +
678 " node. We might be running against an out-of-date server.";
679 *has_nodes = false;
680 syncer::ReadTransaction trans(FROM_HERE, share_handle());
681 syncer::ReadNode type_root_node(&trans);
682 if (type_root_node.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
683 LOG(ERROR) << err_str;
684 return false;
687 // The sync model has user created nodes if the type's root node has any
688 // children.
689 *has_nodes = type_root_node.HasChildren();
690 return true;
693 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
694 DCHECK(CalledOnValidThread());
695 // We only access the cryptographer while holding a transaction.
696 syncer::ReadTransaction trans(FROM_HERE, share_handle());
697 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
698 return !encrypted_types.Has(type_) || trans.GetCryptographer()->is_ready();
701 void GenericChangeProcessor::StartImpl() {
704 syncer::UserShare* GenericChangeProcessor::share_handle() const {
705 DCHECK(CalledOnValidThread());
706 return share_handle_;
709 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
710 DCHECK(CalledOnValidThread());
711 DCHECK(attachment_service_.get());
712 syncer::AttachmentIdList ids;
714 syncer::ReadTransaction trans(FROM_HERE, share_handle());
715 trans.GetAttachmentIdsToUpload(type_, &ids);
717 if (!ids.empty()) {
718 attachment_service_->UploadAttachments(ids);
722 scoped_ptr<syncer::AttachmentService>
723 GenericChangeProcessor::GetAttachmentService() const {
724 return scoped_ptr<syncer::AttachmentService>(
725 new syncer::AttachmentServiceProxy(attachment_service_proxy_));
728 } // namespace sync_driver