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 syncer::ReadNode
root_node(&trans
);
498 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
499 if (root_node
.InitTypeRoot(sync_data_local
.GetDataType()) !=
500 syncer::BaseNode::INIT_OK
) {
501 syncer::SyncError
error(FROM_HERE
,
502 syncer::SyncError::DATATYPE_ERROR
,
503 "Failed to look up root node for type " + type_str
,
505 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
507 LOG(ERROR
) << "Create: no root node.";
510 syncer::WriteNode::InitUniqueByCreationResult result
=
511 sync_node
->InitUniqueByCreation(
512 sync_data_local
.GetDataType(), root_node
, sync_data_local
.GetTag());
513 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
514 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
515 change
.location().ToString() + ", ";
517 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
518 syncer::SyncError error
;
519 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
520 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
521 LOG(ERROR
) << "Create: Empty tag.";
524 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
525 syncer::SyncError error
;
526 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type_
);
527 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
528 LOG(ERROR
) << "Create: Could not create entry.";
531 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
532 syncer::SyncError error
;
534 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
535 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
536 LOG(ERROR
) << "Create: Bad predecessor.";
540 syncer::SyncError error
;
541 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type_
);
542 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
543 LOG(ERROR
) << "Create: Unknown error.";
548 sync_node
->SetTitle(change
.sync_data().GetTitle());
549 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
551 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
552 SetAttachmentMetadata(attachment_ids
, sync_node
);
554 // Return any newly added attachments.
555 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
556 if (merge_result_
.get()) {
557 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
559 return syncer::SyncError();
561 // WARNING: this code is sensitive to compiler optimizations. Be careful
562 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
563 // the compiler attempts to merge it with other calls, losing useful information
564 // in breakpad uploads.
565 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
566 const syncer::SyncChange
& change
,
567 const std::string
& type_str
,
568 const syncer::WriteTransaction
& trans
,
569 syncer::WriteNode
* sync_node
,
570 syncer::AttachmentIdSet
* new_attachments
) {
571 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
572 syncer::BaseNode::InitByLookupResult result
=
573 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
574 sync_data_local
.GetTag());
575 if (result
!= syncer::BaseNode::INIT_OK
) {
576 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
577 change
.location().ToString() + ", ";
578 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
579 syncer::SyncError error
;
580 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
581 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
582 LOG(ERROR
) << "Update: Empty tag.";
584 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
585 syncer::SyncError error
;
586 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type_
);
587 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
588 LOG(ERROR
) << "Update: bad entry.";
590 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
591 syncer::SyncError error
;
592 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type_
);
593 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
594 LOG(ERROR
) << "Update: deleted entry.";
597 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
598 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
599 const sync_pb::EntitySpecifics
& specifics
=
600 sync_node
->GetEntry()->GetSpecifics();
601 CHECK(specifics
.has_encrypted());
602 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
603 const bool agreement
= encrypted_types
.Has(type_
);
604 if (!agreement
&& !can_decrypt
) {
605 syncer::SyncError error
;
606 error
.Reset(FROM_HERE
,
607 "Failed to load encrypted entry, missing key and "
608 "nigori mismatch for " +
611 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
612 LOG(ERROR
) << "Update: encr case 1.";
614 } else if (agreement
&& can_decrypt
) {
615 syncer::SyncError error
;
616 error
.Reset(FROM_HERE
,
617 "Failed to load encrypted entry, we have the key "
618 "and the nigori matches (?!) for " +
621 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
622 LOG(ERROR
) << "Update: encr case 2.";
624 } else if (agreement
) {
625 syncer::SyncError error
;
626 error
.Reset(FROM_HERE
,
627 "Failed to load encrypted entry, missing key and "
628 "the nigori matches for " +
631 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
632 LOG(ERROR
) << "Update: encr case 3.";
635 syncer::SyncError error
;
636 error
.Reset(FROM_HERE
,
637 "Failed to load encrypted entry, we have the key"
638 "(?!) and nigori mismatch for " +
641 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
642 LOG(ERROR
) << "Update: encr case 4.";
648 sync_node
->SetTitle(change
.sync_data().GetTitle());
649 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
650 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
651 SetAttachmentMetadata(attachment_ids
, sync_node
);
653 // Return any newly added attachments.
654 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
656 if (merge_result_
.get()) {
657 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
660 // TODO(sync): Support updating other parts of the sync node (title,
661 // successor, parent, etc.).
662 return syncer::SyncError();
665 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
666 DCHECK(CalledOnValidThread());
668 std::string type_name
= syncer::ModelTypeToString(type_
);
669 std::string err_str
= "Server did not create the top-level " + type_name
+
670 " node. We might be running against an out-of-date server.";
672 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
673 syncer::ReadNode
type_root_node(&trans
);
674 if (type_root_node
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
675 LOG(ERROR
) << err_str
;
679 // The sync model has user created nodes if the type's root node has any
681 *has_nodes
= type_root_node
.HasChildren();
685 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
686 DCHECK(CalledOnValidThread());
687 // We only access the cryptographer while holding a transaction.
688 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
689 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
690 return !encrypted_types
.Has(type_
) || trans
.GetCryptographer()->is_ready();
693 void GenericChangeProcessor::StartImpl() {
696 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
697 DCHECK(CalledOnValidThread());
698 return share_handle_
;
701 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
702 DCHECK(CalledOnValidThread());
703 DCHECK(attachment_service_
.get());
704 syncer::AttachmentIdList ids
;
706 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
707 trans
.GetAttachmentIdsToUpload(type_
, &ids
);
710 attachment_service_
->UploadAttachments(ids
);
714 scoped_ptr
<syncer::AttachmentService
>
715 GenericChangeProcessor::GetAttachmentService() const {
716 return scoped_ptr
<syncer::AttachmentService
>(
717 new syncer::AttachmentServiceProxy(attachment_service_proxy_
));
720 } // namespace sync_driver