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
{
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
) ==
33 write_node
->SetPasswordSpecifics(
34 entity_specifics
.password().client_only_encrypted_data());
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();
48 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
49 void SetAttachmentMetadata(const syncer::AttachmentIdList
& attachment_ids
,
50 syncer::WriteNode
* write_node
) {
52 sync_pb::AttachmentMetadata attachment_metadata
;
54 attachment_ids
.begin(),
56 RepeatedFieldBackInserter(attachment_metadata
.mutable_record()),
57 AttachmentIdToRecord
);
58 write_node
->SetAttachmentMetadata(attachment_metadata
);
61 syncer::SyncData
BuildRemoteSyncData(
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(),
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
,
83 read_node
.GetModificationTime(),
85 attachment_service_proxy
);
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
),
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();
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
,
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_
)));
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(
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
);
170 syncer_changes_
.push_back(syncer::SyncChange(
172 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
177 void GenericChangeProcessor::CommitChangesFromSyncModel() {
178 DCHECK(CalledOnValidThread());
179 if (syncer_changes_
.empty())
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.",
187 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
190 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
192 syncer_changes_
.clear();
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
);
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.",
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-"
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(
264 syncer::SyncError::DATATYPE_ERROR
,
265 "Failed to fetch child node for type " + type_name
+ ".",
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())
283 syncer::GetModelTypeFromSpecificsFieldNumber(
284 context_proto
.data_type_id()));
285 *context
= context_proto
.context();
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
)
295 // Subtract one to account for type's root node.
296 return root
.GetTotalNodeCount() - 1;
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
,
316 "could not find entry matching the lookup criteria.",
318 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
319 LOG(ERROR
) << "Delete: Bad entry.";
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.";
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.";
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.",
341 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
342 LOG(ERROR
) << "Delete: Failed precondition.";
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.";
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();
365 syncer::SyncError
error(
367 syncer::SyncError::DATATYPE_ERROR
,
368 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
369 change
.location().ToString(),
371 error_handler
->OnSingleDataTypeUnrecoverableError(error
);
376 syncer::BaseNode::InitByLookupResult result
=
377 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
378 if (result
!= syncer::BaseNode::INIT_OK
) {
379 return LogLookupFailure(
381 "Failed to delete " + type_str
+ " node. Local data. " +
382 change
.location().ToString(),
383 type
, error_handler
);
386 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
387 syncer::SyncDataRemote(change
.sync_data()).GetId());
388 if (result
!= syncer::BaseNode::INIT_OK
) {
389 return LogLookupFailure(
391 "Failed to delete " + type_str
+ " node. Non-local data. " +
392 change
.location().ToString(),
393 type
, error_handler
);
396 if (IsActOnceDataType(type
))
400 return syncer::SyncError();
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();
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());
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
);
440 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
441 syncer::SyncError error
= HandleActionUpdate(
442 change
, type_str
, trans
, &sync_node
, &new_attachments
);
447 syncer::SyncError
error(
449 syncer::SyncError::DATATYPE_ERROR
,
450 "Received unset SyncChange in the change processor, " +
451 change
.location().ToString(),
453 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
455 LOG(ERROR
) << "Unset sync change.";
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(
466 syncer::SyncError::DATATYPE_ERROR
,
467 "Datatype performs attachment operation without initializing "
470 error_handler()->OnSingleDataTypeUnrecoverableError(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,
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
,
504 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
506 LOG(ERROR
) << "Create: no root node.";
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() + ", ";
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.";
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.";
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.";
537 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
538 syncer::SyncError error
;
540 FROM_HERE
, error_prefix
+ "failed to set predecessor", type_
);
541 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
542 LOG(ERROR
) << "Create: Bad predecessor.";
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.";
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.";
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.";
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.";
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 " +
619 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
620 LOG(ERROR
) << "Update: encr case 1.";
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 " +
629 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
630 LOG(ERROR
) << "Update: encr case 2.";
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 " +
639 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
640 LOG(ERROR
) << "Update: encr case 3.";
643 syncer::SyncError error
;
644 error
.Reset(FROM_HERE
,
645 "Failed to load encrypted entry, we have the key"
646 "(?!) and nigori mismatch for " +
649 error_handler()->OnSingleDataTypeUnrecoverableError(error
);
650 LOG(ERROR
) << "Update: encr case 4.";
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());
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.";
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
;
687 // The sync model has user created nodes if the type's root node has any
689 *has_nodes
= type_root_node
.HasChildren();
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
);
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