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 "components/sync_driver/sync_client.h"
13 #include "sync/api/sync_change.h"
14 #include "sync/api/sync_error.h"
15 #include "sync/api/syncable_service.h"
16 #include "sync/internal_api/public/base_node.h"
17 #include "sync/internal_api/public/change_record.h"
18 #include "sync/internal_api/public/read_node.h"
19 #include "sync/internal_api/public/read_transaction.h"
20 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
21 #include "sync/internal_api/public/write_node.h"
22 #include "sync/internal_api/public/write_transaction.h"
23 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
25 namespace sync_driver
{
29 const int kContextSizeLimit
= 1024; // Datatype context size limit.
31 void SetNodeSpecifics(const sync_pb::EntitySpecifics
& entity_specifics
,
32 syncer::WriteNode
* write_node
) {
33 if (syncer::GetModelTypeFromSpecifics(entity_specifics
) ==
35 write_node
->SetPasswordSpecifics(
36 entity_specifics
.password().client_only_encrypted_data());
38 write_node
->SetEntitySpecifics(entity_specifics
);
42 // Helper function to convert AttachmentId to AttachmentMetadataRecord.
43 sync_pb::AttachmentMetadataRecord
AttachmentIdToRecord(
44 const syncer::AttachmentId
& attachment_id
) {
45 sync_pb::AttachmentMetadataRecord record
;
46 *record
.mutable_id() = attachment_id
.GetProto();
50 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
51 void SetAttachmentMetadata(const syncer::AttachmentIdList
& attachment_ids
,
52 syncer::WriteNode
* write_node
) {
54 sync_pb::AttachmentMetadata attachment_metadata
;
56 attachment_ids
.begin(),
58 RepeatedFieldBackInserter(attachment_metadata
.mutable_record()),
59 AttachmentIdToRecord
);
60 write_node
->SetAttachmentMetadata(attachment_metadata
);
63 syncer::SyncData
BuildRemoteSyncData(
65 const syncer::BaseNode
& read_node
,
66 const syncer::AttachmentServiceProxy
& attachment_service_proxy
) {
67 const syncer::AttachmentIdList
& attachment_ids
= read_node
.GetAttachmentIds();
68 // Use the specifics of non-password datatypes directly (encryption has
69 // already been handled).
70 if (read_node
.GetModelType() != syncer::PASSWORDS
) {
71 return syncer::SyncData::CreateRemoteData(sync_id
,
72 read_node
.GetEntitySpecifics(),
73 read_node
.GetModificationTime(),
75 attachment_service_proxy
);
78 // Passwords must be accessed differently, to account for their encryption,
79 // and stored into a temporary EntitySpecifics.
80 sync_pb::EntitySpecifics password_holder
;
81 password_holder
.mutable_password()->mutable_client_only_encrypted_data()->
82 CopyFrom(read_node
.GetPasswordSpecifics());
83 return syncer::SyncData::CreateRemoteData(sync_id
,
85 read_node
.GetModificationTime(),
87 attachment_service_proxy
);
92 GenericChangeProcessor::GenericChangeProcessor(
93 syncer::ModelType type
,
94 DataTypeErrorHandler
* error_handler
,
95 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
96 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
97 syncer::UserShare
* user_share
,
98 SyncClient
* sync_client
,
99 scoped_ptr
<syncer::AttachmentStoreForSync
> attachment_store
)
100 : ChangeProcessor(error_handler
),
102 local_service_(local_service
),
103 merge_result_(merge_result
),
104 share_handle_(user_share
),
105 weak_ptr_factory_(this) {
106 DCHECK(CalledOnValidThread());
107 DCHECK_NE(type_
, syncer::UNSPECIFIED
);
108 if (attachment_store
) {
109 std::string store_birthday
;
111 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
112 store_birthday
= trans
.GetStoreBirthday();
114 attachment_service_
=
115 sync_client
->GetSyncApiComponentFactory()->CreateAttachmentService(
116 attachment_store
.Pass(), *user_share
, store_birthday
, type
, this);
117 attachment_service_weak_ptr_factory_
.reset(
118 new base::WeakPtrFactory
<syncer::AttachmentService
>(
119 attachment_service_
.get()));
120 attachment_service_proxy_
= syncer::AttachmentServiceProxy(
121 base::ThreadTaskRunnerHandle::Get(),
122 attachment_service_weak_ptr_factory_
->GetWeakPtr());
123 UploadAllAttachmentsNotOnServer();
125 attachment_service_proxy_
= syncer::AttachmentServiceProxy(
126 base::ThreadTaskRunnerHandle::Get(),
127 base::WeakPtr
<syncer::AttachmentService
>());
131 GenericChangeProcessor::~GenericChangeProcessor() {
132 DCHECK(CalledOnValidThread());
135 void GenericChangeProcessor::ApplyChangesFromSyncModel(
136 const syncer::BaseTransaction
* trans
,
138 const syncer::ImmutableChangeRecordList
& changes
) {
139 DCHECK(CalledOnValidThread());
140 DCHECK(syncer_changes_
.empty());
141 for (syncer::ChangeRecordList::const_iterator it
=
142 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
143 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
144 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
145 if (it
->specifics
.has_password()) {
146 DCHECK(it
->extra
.get());
147 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
148 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
149 CopyFrom(it
->extra
->unencrypted());
151 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
152 syncer_changes_
.push_back(syncer::SyncChange(
153 FROM_HERE
, syncer::SyncChange::ACTION_DELETE
,
154 syncer::SyncData::CreateRemoteData(
155 it
->id
, specifics
? *specifics
: it
->specifics
, base::Time(),
156 empty_list_of_attachment_ids
, attachment_service_proxy_
)));
158 syncer::SyncChange::SyncChangeType action
=
159 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
160 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
161 // Need to load specifics from node.
162 syncer::ReadNode
read_node(trans
);
163 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
164 syncer::SyncError
error(
166 syncer::SyncError::DATATYPE_ERROR
,
167 "Failed to look up data for received change with id " +
168 base::Int64ToString(it
->id
),
169 syncer::GetModelTypeFromSpecifics(it
->specifics
));
170 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
173 syncer_changes_
.push_back(syncer::SyncChange(
175 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
180 void GenericChangeProcessor::CommitChangesFromSyncModel() {
181 DCHECK(CalledOnValidThread());
182 if (syncer_changes_
.empty())
184 if (!local_service_
.get()) {
185 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
186 syncer::SyncError
error(FROM_HERE
,
187 syncer::SyncError::DATATYPE_ERROR
,
188 "Local service destroyed.",
190 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
193 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
195 syncer_changes_
.clear();
197 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
200 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
201 syncer::ModelType type
) const {
202 DCHECK_EQ(type_
, type
);
203 // This is slow / memory intensive. Should be used sparingly by datatypes.
204 syncer::SyncDataList data
;
205 GetAllSyncDataReturnError(&data
);
209 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
210 syncer::ModelType type
,
211 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
212 const std::string
& context
) {
213 DCHECK(syncer::ProtocolTypes().Has(type
));
214 DCHECK_EQ(type_
, type
);
216 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
217 return syncer::SyncError(FROM_HERE
,
218 syncer::SyncError::DATATYPE_ERROR
,
219 "Context size limit exceeded.",
223 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
224 trans
.SetDataTypeContext(type
, refresh_status
, context
);
226 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
227 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
229 return syncer::SyncError();
232 void GenericChangeProcessor::OnAttachmentUploaded(
233 const syncer::AttachmentId
& attachment_id
) {
234 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
235 trans
.UpdateEntriesMarkAttachmentAsOnServer(attachment_id
);
238 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
239 syncer::SyncDataList
* current_sync_data
) const {
240 DCHECK(CalledOnValidThread());
241 std::string type_name
= syncer::ModelTypeToString(type_
);
242 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
243 syncer::ReadNode
root(&trans
);
244 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
245 syncer::SyncError
error(FROM_HERE
,
246 syncer::SyncError::DATATYPE_ERROR
,
247 "Server did not create the top-level " + type_name
+
248 " node. We might be running against an out-of-"
254 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
255 DCHECK_NE(type_
, syncer::BOOKMARKS
);
257 std::vector
<int64
> child_ids
;
258 root
.GetChildIds(&child_ids
);
260 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
261 it
!= child_ids
.end(); ++it
) {
262 syncer::ReadNode
sync_child_node(&trans
);
263 if (sync_child_node
.InitByIdLookup(*it
) !=
264 syncer::BaseNode::INIT_OK
) {
265 syncer::SyncError
error(
267 syncer::SyncError::DATATYPE_ERROR
,
268 "Failed to fetch child node for type " + type_name
+ ".",
272 current_sync_data
->push_back(BuildRemoteSyncData(
273 sync_child_node
.GetId(), sync_child_node
, attachment_service_proxy_
));
275 return syncer::SyncError();
278 bool GenericChangeProcessor::GetDataTypeContext(std::string
* context
) const {
279 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
280 sync_pb::DataTypeContext context_proto
;
281 trans
.GetDataTypeContext(type_
, &context_proto
);
282 if (!context_proto
.has_context())
286 syncer::GetModelTypeFromSpecificsFieldNumber(
287 context_proto
.data_type_id()));
288 *context
= context_proto
.context();
292 int GenericChangeProcessor::GetSyncCount() {
293 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
294 syncer::ReadNode
root(&trans
);
295 if (root
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
)
298 // Subtract one to account for type's root node.
299 return root
.GetTotalNodeCount() - 1;
304 // WARNING: this code is sensitive to compiler optimizations. Be careful
305 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
306 // the compiler attempts to merge it with other calls, losing useful information
307 // in breakpad uploads.
308 syncer::SyncError
LogLookupFailure(
309 syncer::BaseNode::InitByLookupResult lookup_result
,
310 const tracked_objects::Location
& from_here
,
311 const std::string
& error_prefix
,
312 syncer::ModelType type
,
313 DataTypeErrorHandler
* error_handler
) {
314 switch (lookup_result
) {
315 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
316 syncer::SyncError error
;
317 error
.Reset(from_here
,
319 "could not find entry matching the lookup criteria.",
321 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
322 LOG(ERROR
) << "Delete: Bad entry.";
325 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
326 syncer::SyncError error
;
327 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
328 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
329 LOG(ERROR
) << "Delete: Deleted entry.";
332 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
333 syncer::SyncError error
;
334 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
335 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
336 LOG(ERROR
) << "Delete: Undecryptable entry.";
339 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
340 syncer::SyncError error
;
341 error
.Reset(from_here
,
342 error_prefix
+ "a precondition was not met for calling init.",
344 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
345 LOG(ERROR
) << "Delete: Failed precondition.";
349 syncer::SyncError error
;
350 // Should have listed all the possible error cases above.
351 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
352 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
353 LOG(ERROR
) << "Delete: Unknown error.";
359 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
360 syncer::ModelType type
,
361 const std::string
& type_str
,
362 syncer::WriteNode
* node
,
363 DataTypeErrorHandler
* error_handler
) {
364 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
365 if (change
.sync_data().IsLocal()) {
366 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
368 syncer::SyncError
error(
370 syncer::SyncError::DATATYPE_ERROR
,
371 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
372 change
.location().ToString(),
374 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
379 syncer::BaseNode::InitByLookupResult result
=
380 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
381 if (result
!= syncer::BaseNode::INIT_OK
) {
382 return LogLookupFailure(
384 "Failed to delete " + type_str
+ " node. Local data. " +
385 change
.location().ToString(),
386 type
, error_handler
);
389 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
390 syncer::SyncDataRemote(change
.sync_data()).GetId());
391 if (result
!= syncer::BaseNode::INIT_OK
) {
392 return LogLookupFailure(
394 "Failed to delete " + type_str
+ " node. Non-local data. " +
395 change
.location().ToString(),
396 type
, error_handler
);
399 if (IsActOnceDataType(type
))
403 return syncer::SyncError();
408 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
409 const tracked_objects::Location
& from_here
,
410 const syncer::SyncChangeList
& list_of_changes
) {
411 DCHECK(CalledOnValidThread());
413 if (list_of_changes
.empty()) {
414 // No work. Exit without entering WriteTransaction.
415 return syncer::SyncError();
418 // Keep track of brand new attachments so we can persist them on this device
419 // and upload them to the server.
420 syncer::AttachmentIdSet new_attachments
;
422 syncer::WriteTransaction
trans(from_here
, share_handle());
424 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
425 iter
!= list_of_changes
.end();
427 const syncer::SyncChange
& change
= *iter
;
428 DCHECK_EQ(change
.sync_data().GetDataType(), type_
);
429 std::string type_str
= syncer::ModelTypeToString(type_
);
430 syncer::WriteNode
sync_node(&trans
);
431 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
432 syncer::SyncError error
=
433 AttemptDelete(change
, type_
, type_str
, &sync_node
, error_handler());
438 if (merge_result_
.get()) {
439 merge_result_
->set_num_items_deleted(
440 merge_result_
->num_items_deleted() + 1);
442 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
443 syncer::SyncError error
= HandleActionAdd(
444 change
, type_str
, trans
, &sync_node
, &new_attachments
);
448 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
449 syncer::SyncError error
= HandleActionUpdate(
450 change
, type_str
, trans
, &sync_node
, &new_attachments
);
455 syncer::SyncError
error(
457 syncer::SyncError::DATATYPE_ERROR
,
458 "Received unset SyncChange in the change processor, " +
459 change
.location().ToString(),
461 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
463 LOG(ERROR
) << "Unset sync change.";
468 if (!new_attachments
.empty()) {
469 // If datatype uses attachments it should have supplied attachment store
470 // which would initialize attachment_service_. Fail if it isn't so.
471 if (!attachment_service_
.get()) {
472 syncer::SyncError
error(
474 syncer::SyncError::DATATYPE_ERROR
,
475 "Datatype performs attachment operation without initializing "
478 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
482 syncer::AttachmentIdList ids_to_upload
;
483 ids_to_upload
.reserve(new_attachments
.size());
484 std::copy(new_attachments
.begin(), new_attachments
.end(),
485 std::back_inserter(ids_to_upload
));
486 attachment_service_
->UploadAttachments(ids_to_upload
);
489 return syncer::SyncError();
492 // WARNING: this code is sensitive to compiler optimizations. Be careful
493 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
494 // the compiler attempts to merge it with other calls, losing useful information
495 // in breakpad uploads.
496 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
497 const syncer::SyncChange
& change
,
498 const std::string
& type_str
,
499 const syncer::WriteTransaction
& trans
,
500 syncer::WriteNode
* sync_node
,
501 syncer::AttachmentIdSet
* new_attachments
) {
502 // TODO(sync): Handle other types of creation (custom parents, folders,
504 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
505 syncer::WriteNode::InitUniqueByCreationResult result
=
506 sync_node
->InitUniqueByCreation(sync_data_local
.GetDataType(),
507 sync_data_local
.GetTag());
508 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
509 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
510 change
.location().ToString() + ", ";
512 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
513 syncer::SyncError error
;
514 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
515 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
516 LOG(ERROR
) << "Create: Empty tag.";
519 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
520 syncer::SyncError error
;
521 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type_
);
522 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
523 LOG(ERROR
) << "Create: Could not create entry.";
526 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
527 syncer::SyncError error
;
529 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
530 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
531 LOG(ERROR
) << "Create: Bad predecessor.";
535 syncer::SyncError error
;
536 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type_
);
537 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
538 LOG(ERROR
) << "Create: Unknown error.";
543 sync_node
->SetTitle(change
.sync_data().GetTitle());
544 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
546 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
547 SetAttachmentMetadata(attachment_ids
, sync_node
);
549 // Return any newly added attachments.
550 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
551 if (merge_result_
.get()) {
552 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
554 return syncer::SyncError();
556 // WARNING: this code is sensitive to compiler optimizations. Be careful
557 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
558 // the compiler attempts to merge it with other calls, losing useful information
559 // in breakpad uploads.
560 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
561 const syncer::SyncChange
& change
,
562 const std::string
& type_str
,
563 const syncer::WriteTransaction
& trans
,
564 syncer::WriteNode
* sync_node
,
565 syncer::AttachmentIdSet
* new_attachments
) {
566 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
567 syncer::BaseNode::InitByLookupResult result
=
568 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
569 sync_data_local
.GetTag());
570 if (result
!= syncer::BaseNode::INIT_OK
) {
571 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
572 change
.location().ToString() + ", ";
573 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
574 syncer::SyncError error
;
575 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type_
);
576 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
577 LOG(ERROR
) << "Update: Empty tag.";
579 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
580 syncer::SyncError error
;
581 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type_
);
582 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
583 LOG(ERROR
) << "Update: bad entry.";
585 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
586 syncer::SyncError error
;
587 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type_
);
588 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
589 LOG(ERROR
) << "Update: deleted entry.";
592 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
593 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
594 const sync_pb::EntitySpecifics
& specifics
=
595 sync_node
->GetEntry()->GetSpecifics();
596 CHECK(specifics
.has_encrypted());
597 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
598 const bool agreement
= encrypted_types
.Has(type_
);
599 if (!agreement
&& !can_decrypt
) {
600 syncer::SyncError error
;
601 error
.Reset(FROM_HERE
,
602 "Failed to load encrypted entry, missing key and "
603 "nigori mismatch for " +
606 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
607 LOG(ERROR
) << "Update: encr case 1.";
609 } else if (agreement
&& can_decrypt
) {
610 syncer::SyncError error
;
611 error
.Reset(FROM_HERE
,
612 "Failed to load encrypted entry, we have the key "
613 "and the nigori matches (?!) for " +
616 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
617 LOG(ERROR
) << "Update: encr case 2.";
619 } else if (agreement
) {
620 syncer::SyncError error
;
621 error
.Reset(FROM_HERE
,
622 "Failed to load encrypted entry, missing key and "
623 "the nigori matches for " +
626 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
627 LOG(ERROR
) << "Update: encr case 3.";
630 syncer::SyncError error
;
631 error
.Reset(FROM_HERE
,
632 "Failed to load encrypted entry, we have the key"
633 "(?!) and nigori mismatch for " +
636 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
637 LOG(ERROR
) << "Update: encr case 4.";
643 sync_node
->SetTitle(change
.sync_data().GetTitle());
644 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
645 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
646 SetAttachmentMetadata(attachment_ids
, sync_node
);
648 // Return any newly added attachments.
649 new_attachments
->insert(attachment_ids
.begin(), attachment_ids
.end());
651 if (merge_result_
.get()) {
652 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
655 // TODO(sync): Support updating other parts of the sync node (title,
656 // successor, parent, etc.).
657 return syncer::SyncError();
660 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
661 DCHECK(CalledOnValidThread());
663 std::string type_name
= syncer::ModelTypeToString(type_
);
664 std::string err_str
= "Server did not create the top-level " + type_name
+
665 " node. We might be running against an out-of-date server.";
667 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
668 syncer::ReadNode
type_root_node(&trans
);
669 if (type_root_node
.InitTypeRoot(type_
) != syncer::BaseNode::INIT_OK
) {
670 LOG(ERROR
) << err_str
;
674 // The sync model has user created nodes if the type's root node has any
676 *has_nodes
= type_root_node
.HasChildren();
680 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
681 DCHECK(CalledOnValidThread());
682 // We only access the cryptographer while holding a transaction.
683 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
684 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
685 return !encrypted_types
.Has(type_
) || trans
.GetCryptographer()->is_ready();
688 void GenericChangeProcessor::StartImpl() {
691 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
692 DCHECK(CalledOnValidThread());
693 return share_handle_
;
696 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
697 DCHECK(CalledOnValidThread());
698 DCHECK(attachment_service_
.get());
699 syncer::AttachmentIdList ids
;
701 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
702 trans
.GetAttachmentIdsToUpload(type_
, &ids
);
705 attachment_service_
->UploadAttachments(ids
);
709 scoped_ptr
<syncer::AttachmentService
>
710 GenericChangeProcessor::GetAttachmentService() const {
711 return scoped_ptr
<syncer::AttachmentService
>(
712 new syncer::AttachmentServiceProxy(attachment_service_proxy_
));
715 } // namespace sync_driver