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 "base/thread_task_runner_handle.h"
11 #include "components/sync_driver/sync_api_component_factory.h"
12 #include "sync/api/sync_change.h"
13 #include "sync/api/sync_error.h"
14 #include "sync/api/syncable_service.h"
15 #include "sync/internal_api/public/base_node.h"
16 #include "sync/internal_api/public/change_record.h"
17 #include "sync/internal_api/public/read_node.h"
18 #include "sync/internal_api/public/read_transaction.h"
19 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
20 #include "sync/internal_api/public/write_node.h"
21 #include "sync/internal_api/public/write_transaction.h"
22 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
24 namespace sync_driver
{
28 const int kContextSizeLimit
= 1024; // Datatype context size limit.
30 void SetNodeSpecifics(const sync_pb::EntitySpecifics
& entity_specifics
,
31 syncer::WriteNode
* write_node
) {
32 if (syncer::GetModelTypeFromSpecifics(entity_specifics
) ==
34 write_node
->SetPasswordSpecifics(
35 entity_specifics
.password().client_only_encrypted_data());
37 write_node
->SetEntitySpecifics(entity_specifics
);
41 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
42 sync_pb::AttachmentMetadataRecord
AttachmentIdToRecord(
43 const syncer::AttachmentId
& attachment_id
) {
44 sync_pb::AttachmentMetadataRecord record
;
45 *record
.mutable_id() = attachment_id
.GetProto();
49 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
50 void SetAttachmentMetadata(const syncer::AttachmentIdList
& attachment_ids
,
51 syncer::WriteNode
* write_node
) {
53 sync_pb::AttachmentMetadata attachment_metadata
;
55 attachment_ids
.begin(),
57 RepeatedFieldBackInserter(attachment_metadata
.mutable_record()),
58 AttachmentIdToRecord
);
59 write_node
->SetAttachmentMetadata(attachment_metadata
);
62 syncer::SyncData
BuildRemoteSyncData(
64 const syncer::BaseNode
& read_node
,
65 const syncer::AttachmentServiceProxy
& attachment_service_proxy
) {
66 const syncer::AttachmentIdList
& attachment_ids
= read_node
.GetAttachmentIds();
67 // Use the specifics of non-password datatypes directly (encryption has
68 // already been handled).
69 if (read_node
.GetModelType() != syncer::PASSWORDS
) {
70 return syncer::SyncData::CreateRemoteData(sync_id
,
71 read_node
.GetEntitySpecifics(),
72 read_node
.GetModificationTime(),
74 attachment_service_proxy
);
77 // Passwords must be accessed differently, to account for their encryption,
78 // and stored into a temporary EntitySpecifics.
79 sync_pb::EntitySpecifics password_holder
;
80 password_holder
.mutable_password()->mutable_client_only_encrypted_data()->
81 CopyFrom(read_node
.GetPasswordSpecifics());
82 return syncer::SyncData::CreateRemoteData(sync_id
,
84 read_node
.GetModificationTime(),
86 attachment_service_proxy
);
91 GenericChangeProcessor::GenericChangeProcessor(
92 syncer::ModelType type
,
93 DataTypeErrorHandler
* error_handler
,
94 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
95 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
96 syncer::UserShare
* user_share
,
97 SyncApiComponentFactory
* sync_factory
,
98 scoped_ptr
<syncer::AttachmentStoreForSync
> attachment_store
)
99 : ChangeProcessor(error_handler
),
101 local_service_(local_service
),
102 merge_result_(merge_result
),
103 share_handle_(user_share
),
104 weak_ptr_factory_(this) {
105 DCHECK(CalledOnValidThread());
106 DCHECK_NE(type_
, syncer::UNSPECIFIED
);
107 if (attachment_store
) {
108 std::string store_birthday
;
110 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
111 store_birthday
= trans
.GetStoreBirthday();
113 attachment_service_
= sync_factory
->CreateAttachmentService(
114 attachment_store
.Pass(), *user_share
, store_birthday
, type
, this);
115 attachment_service_weak_ptr_factory_
.reset(
116 new base::WeakPtrFactory
<syncer::AttachmentService
>(
117 attachment_service_
.get()));
118 attachment_service_proxy_
= syncer::AttachmentServiceProxy(
119 base::ThreadTaskRunnerHandle::Get(),
120 attachment_service_weak_ptr_factory_
->GetWeakPtr());
121 UploadAllAttachmentsNotOnServer();
123 attachment_service_proxy_
= syncer::AttachmentServiceProxy(
124 base::ThreadTaskRunnerHandle::Get(),
125 base::WeakPtr
<syncer::AttachmentService
>());
129 GenericChangeProcessor::~GenericChangeProcessor() {
130 DCHECK(CalledOnValidThread());
133 void GenericChangeProcessor::ApplyChangesFromSyncModel(
134 const syncer::BaseTransaction
* trans
,
136 const syncer::ImmutableChangeRecordList
& changes
) {
137 DCHECK(CalledOnValidThread());
138 DCHECK(syncer_changes_
.empty());
139 for (syncer::ChangeRecordList::const_iterator it
=
140 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
141 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
142 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
143 if (it
->specifics
.has_password()) {
144 DCHECK(it
->extra
.get());
145 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
146 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
147 CopyFrom(it
->extra
->unencrypted());
149 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
150 syncer_changes_
.push_back(syncer::SyncChange(
151 FROM_HERE
, syncer::SyncChange::ACTION_DELETE
,
152 syncer::SyncData::CreateRemoteData(
153 it
->id
, specifics
? *specifics
: it
->specifics
, base::Time(),
154 empty_list_of_attachment_ids
, attachment_service_proxy_
)));
156 syncer::SyncChange::SyncChangeType action
=
157 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
158 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
159 // Need to load specifics from node.
160 syncer::ReadNode
read_node(trans
);
161 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
162 syncer::SyncError
error(
164 syncer::SyncError::DATATYPE_ERROR
,
165 "Failed to look up data for received change with id " +
166 base::Int64ToString(it
->id
),
167 syncer::GetModelTypeFromSpecifics(it
->specifics
));
168 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
171 syncer_changes_
.push_back(syncer::SyncChange(
173 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
178 void GenericChangeProcessor::CommitChangesFromSyncModel() {
179 DCHECK(CalledOnValidThread());
180 if (syncer_changes_
.empty())
182 if (!local_service_
.get()) {
183 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
184 syncer::SyncError
error(FROM_HERE
,
185 syncer::SyncError::DATATYPE_ERROR
,
186 "Local service destroyed.",
188 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
191 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
193 syncer_changes_
.clear();
195 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
198 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
199 syncer::ModelType type
) const {
200 DCHECK_EQ(type_
, type
);
201 // This is slow / memory intensive. Should be used sparingly by datatypes.
202 syncer::SyncDataList data
;
203 GetAllSyncDataReturnError(&data
);
207 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
208 syncer::ModelType type
,
209 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
210 const std::string
& context
) {
211 DCHECK(syncer::ProtocolTypes().Has(type
));
212 DCHECK_EQ(type_
, type
);
214 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
215 return syncer::SyncError(FROM_HERE
,
216 syncer::SyncError::DATATYPE_ERROR
,
217 "Context size limit exceeded.",
221 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
222 trans
.SetDataTypeContext(type
, refresh_status
, context
);
224 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
225 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
227 return syncer::SyncError();
230 void GenericChangeProcessor::OnAttachmentUploaded(
231 const syncer::AttachmentId
& attachment_id
) {
232 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
233 trans
.UpdateEntriesMarkAttachmentAsOnServer(attachment_id
);
236 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
237 syncer::SyncDataList
* current_sync_data
) const {
238 DCHECK(CalledOnValidThread());
239 std::string type_name
= syncer::ModelTypeToString(type_
);
240 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
241 syncer::ReadNode
root(&trans
);
242 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
243 syncer::SyncError
error(FROM_HERE
,
244 syncer::SyncError::DATATYPE_ERROR
,
245 "Server did not create the top-level " + type_name
+
246 " node. We might be running against an out-of-"
252 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
253 DCHECK_NE(type_
, syncer::BOOKMARKS
);
255 std::vector
<int64
> child_ids
;
256 root
.GetChildIds(&child_ids
);
258 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
259 it
!= child_ids
.end(); ++it
) {
260 syncer::ReadNode
sync_child_node(&trans
);
261 if (sync_child_node
.InitByIdLookup(*it
) !=
262 syncer::BaseNode::INIT_OK
) {
263 syncer::SyncError
error(
265 syncer::SyncError::DATATYPE_ERROR
,
266 "Failed to fetch child node for type " + type_name
+ ".",
270 current_sync_data
->push_back(BuildRemoteSyncData(
271 sync_child_node
.GetId(), sync_child_node
, attachment_service_proxy_
));
273 return syncer::SyncError();
276 bool GenericChangeProcessor::GetDataTypeContext(std::string
* context
) const {
277 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
278 sync_pb::DataTypeContext context_proto
;
279 trans
.GetDataTypeContext(type_
, &context_proto
);
280 if (!context_proto
.has_context())
284 syncer::GetModelTypeFromSpecificsFieldNumber(
285 context_proto
.data_type_id()));
286 *context
= context_proto
.context();
290 int GenericChangeProcessor::GetSyncCount() {
291 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
292 syncer::ReadNode
root(&trans
);
293 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
)
296 // Subtract one to account for type's root node.
297 return root
.GetTotalNodeCount() - 1;
302 // WARNING: this code is sensitive to compiler optimizations. Be careful
303 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
304 // the compiler attempts to merge it with other calls, losing useful information
305 // in breakpad uploads.
306 syncer::SyncError
LogLookupFailure(
307 syncer::BaseNode::InitByLookupResult lookup_result
,
308 const tracked_objects::Location
& from_here
,
309 const std::string
& error_prefix
,
310 syncer::ModelType type
,
311 DataTypeErrorHandler
* error_handler
) {
312 switch (lookup_result
) {
313 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
314 syncer::SyncError error
;
315 error
.Reset(from_here
,
317 "could not find entry matching the lookup criteria.",
319 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
320 LOG(ERROR
) << "Delete: Bad entry.";
323 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
324 syncer::SyncError error
;
325 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
326 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
327 LOG(ERROR
) << "Delete: Deleted entry.";
330 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
331 syncer::SyncError error
;
332 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
333 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
334 LOG(ERROR
) << "Delete: Undecryptable entry.";
337 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
338 syncer::SyncError error
;
339 error
.Reset(from_here
,
340 error_prefix
+ "a precondition was not met for calling init.",
342 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
343 LOG(ERROR
) << "Delete: Failed precondition.";
347 syncer::SyncError error
;
348 // Should have listed all the possible error cases above.
349 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
350 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
351 LOG(ERROR
) << "Delete: Unknown error.";
357 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
358 syncer::ModelType type
,
359 const std::string
& type_str
,
360 syncer::WriteNode
* node
,
361 DataTypeErrorHandler
* error_handler
) {
362 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
363 if (change
.sync_data().IsLocal()) {
364 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
366 syncer::SyncError
error(
368 syncer::SyncError::DATATYPE_ERROR
,
369 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
370 change
.location().ToString(),
372 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
377 syncer::BaseNode::InitByLookupResult result
=
378 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
379 if (result
!= syncer::BaseNode::INIT_OK
) {
380 return LogLookupFailure(
382 "Failed to delete " + type_str
+ " node. Local data. " +
383 change
.location().ToString(),
384 type
, error_handler
);
387 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
388 syncer::SyncDataRemote(change
.sync_data()).GetId());
389 if (result
!= syncer::BaseNode::INIT_OK
) {
390 return LogLookupFailure(
392 "Failed to delete " + type_str
+ " node. Non-local data. " +
393 change
.location().ToString(),
394 type
, error_handler
);
397 if (IsActOnceDataType(type
))
401 return syncer::SyncError();
406 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
407 const tracked_objects::Location
& from_here
,
408 const syncer::SyncChangeList
& list_of_changes
) {
409 DCHECK(CalledOnValidThread());
411 // Keep track of brand new attachments so we can persist them on this device
412 // and upload them to the server.
413 syncer::AttachmentIdSet new_attachments
;
415 syncer::WriteTransaction
trans(from_here
, share_handle());
417 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
418 iter
!= list_of_changes
.end();
420 const syncer::SyncChange
& change
= *iter
;
421 DCHECK_EQ(change
.sync_data().GetDataType(), type_
);
422 std::string type_str
= syncer::ModelTypeToString(type_
);
423 syncer::WriteNode
sync_node(&trans
);
424 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
425 syncer::SyncError error
=
426 AttemptDelete(change
, type_
, type_str
, &sync_node
, error_handler());
431 if (merge_result_
.get()) {
432 merge_result_
->set_num_items_deleted(
433 merge_result_
->num_items_deleted() + 1);
435 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
436 syncer::SyncError error
= HandleActionAdd(
437 change
, type_str
, trans
, &sync_node
, &new_attachments
);
441 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
442 syncer::SyncError error
= HandleActionUpdate(
443 change
, type_str
, trans
, &sync_node
, &new_attachments
);
448 syncer::SyncError
error(
450 syncer::SyncError::DATATYPE_ERROR
,
451 "Received unset SyncChange in the change processor, " +
452 change
.location().ToString(),
454 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
456 LOG(ERROR
) << "Unset sync change.";
461 if (!new_attachments
.empty()) {
462 // If datatype uses attachments it should have supplied attachment store
463 // which would initialize attachment_service_. Fail if it isn't so.
464 if (!attachment_service_
.get()) {
465 syncer::SyncError
error(
467 syncer::SyncError::DATATYPE_ERROR
,
468 "Datatype performs attachment operation without initializing "
471 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
475 syncer::AttachmentIdList ids_to_upload
;
476 ids_to_upload
.reserve(new_attachments
.size());
477 std::copy(new_attachments
.begin(), new_attachments
.end(),
478 std::back_inserter(ids_to_upload
));
479 attachment_service_
->UploadAttachments(ids_to_upload
);
482 return syncer::SyncError();
485 // WARNING: this code is sensitive to compiler optimizations. Be careful
486 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
487 // the compiler attempts to merge it with other calls, losing useful information
488 // in breakpad uploads.
489 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
490 const syncer::SyncChange
& change
,
491 const std::string
& type_str
,
492 const syncer::WriteTransaction
& trans
,
493 syncer::WriteNode
* sync_node
,
494 syncer::AttachmentIdSet
* new_attachments
) {
495 // TODO(sync): Handle other types of creation (custom parents, folders,
497 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
498 syncer::WriteNode::InitUniqueByCreationResult result
=
499 sync_node
->InitUniqueByCreation(sync_data_local
.GetDataType(),
500 sync_data_local
.GetTag());
501 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
502 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
503 change
.location().ToString() + ", ";
505 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
506 syncer::SyncError error
;
507 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
508 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
509 LOG(ERROR
) << "Create: Empty tag.";
512 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
513 syncer::SyncError error
;
514 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type_
);
515 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
516 LOG(ERROR
) << "Create: Could not create entry.";
519 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
520 syncer::SyncError error
;
522 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
523 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
524 LOG(ERROR
) << "Create: Bad predecessor.";
528 syncer::SyncError error
;
529 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type_
);
530 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
531 LOG(ERROR
) << "Create: Unknown error.";
536 sync_node
->SetTitle(change
.sync_data().GetTitle());
537 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
539 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
540 SetAttachmentMetadata(attachment_ids
, sync_node
);
542 // Return any newly added attachments.
543 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
544 if (merge_result_
.get()) {
545 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
547 return syncer::SyncError();
549 // WARNING: this code is sensitive to compiler optimizations. Be careful
550 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
551 // the compiler attempts to merge it with other calls, losing useful information
552 // in breakpad uploads.
553 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
554 const syncer::SyncChange
& change
,
555 const std::string
& type_str
,
556 const syncer::WriteTransaction
& trans
,
557 syncer::WriteNode
* sync_node
,
558 syncer::AttachmentIdSet
* new_attachments
) {
559 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
560 syncer::BaseNode::InitByLookupResult result
=
561 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
562 sync_data_local
.GetTag());
563 if (result
!= syncer::BaseNode::INIT_OK
) {
564 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
565 change
.location().ToString() + ", ";
566 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
567 syncer::SyncError error
;
568 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
569 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
570 LOG(ERROR
) << "Update: Empty tag.";
572 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
573 syncer::SyncError error
;
574 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type_
);
575 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
576 LOG(ERROR
) << "Update: bad entry.";
578 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
579 syncer::SyncError error
;
580 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type_
);
581 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
582 LOG(ERROR
) << "Update: deleted entry.";
585 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
586 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
587 const sync_pb::EntitySpecifics
& specifics
=
588 sync_node
->GetEntry()->GetSpecifics();
589 CHECK(specifics
.has_encrypted());
590 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
591 const bool agreement
= encrypted_types
.Has(type_
);
592 if (!agreement
&& !can_decrypt
) {
593 syncer::SyncError error
;
594 error
.Reset(FROM_HERE
,
595 "Failed to load encrypted entry, missing key and "
596 "nigori mismatch for " +
599 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
600 LOG(ERROR
) << "Update: encr case 1.";
602 } else if (agreement
&& can_decrypt
) {
603 syncer::SyncError error
;
604 error
.Reset(FROM_HERE
,
605 "Failed to load encrypted entry, we have the key "
606 "and the nigori matches (?!) for " +
609 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
610 LOG(ERROR
) << "Update: encr case 2.";
612 } else if (agreement
) {
613 syncer::SyncError error
;
614 error
.Reset(FROM_HERE
,
615 "Failed to load encrypted entry, missing key and "
616 "the nigori matches for " +
619 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
620 LOG(ERROR
) << "Update: encr case 3.";
623 syncer::SyncError error
;
624 error
.Reset(FROM_HERE
,
625 "Failed to load encrypted entry, we have the key"
626 "(?!) and nigori mismatch for " +
629 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
630 LOG(ERROR
) << "Update: encr case 4.";
636 sync_node
->SetTitle(change
.sync_data().GetTitle());
637 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
638 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
639 SetAttachmentMetadata(attachment_ids
, sync_node
);
641 // Return any newly added attachments.
642 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
644 if (merge_result_
.get()) {
645 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
648 // TODO(sync): Support updating other parts of the sync node (title,
649 // successor, parent, etc.).
650 return syncer::SyncError();
653 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
654 DCHECK(CalledOnValidThread());
656 std::string type_name
= syncer::ModelTypeToString(type_
);
657 std::string err_str
= "Server did not create the top-level " + type_name
+
658 " node. We might be running against an out-of-date server.";
660 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
661 syncer::ReadNode
type_root_node(&trans
);
662 if (type_root_node
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
663 LOG(ERROR
) << err_str
;
667 // The sync model has user created nodes if the type's root node has any
669 *has_nodes
= type_root_node
.HasChildren();
673 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
674 DCHECK(CalledOnValidThread());
675 // We only access the cryptographer while holding a transaction.
676 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
677 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
678 return !encrypted_types
.Has(type_
) || trans
.GetCryptographer()->is_ready();
681 void GenericChangeProcessor::StartImpl() {
684 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
685 DCHECK(CalledOnValidThread());
686 return share_handle_
;
689 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
690 DCHECK(CalledOnValidThread());
691 DCHECK(attachment_service_
.get());
692 syncer::AttachmentIdList ids
;
694 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
695 trans
.GetAttachmentIdsToUpload(type_
, &ids
);
698 attachment_service_
->UploadAttachments(ids
);
702 scoped_ptr
<syncer::AttachmentService
>
703 GenericChangeProcessor::GetAttachmentService() const {
704 return scoped_ptr
<syncer::AttachmentService
>(
705 new syncer::AttachmentServiceProxy(attachment_service_proxy_
));
708 } // namespace sync_driver