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 browser_sync
{
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 DataTypeErrorHandler
* error_handler
,
92 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
93 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
94 syncer::UserShare
* user_share
,
95 SyncApiComponentFactory
* sync_factory
)
96 : ChangeProcessor(error_handler
),
97 local_service_(local_service
),
98 merge_result_(merge_result
),
99 share_handle_(user_share
),
100 attachment_service_(sync_factory
->CreateAttachmentService(this)),
101 attachment_service_weak_ptr_factory_(attachment_service_
.get()),
102 attachment_service_proxy_(
103 base::MessageLoopProxy::current(),
104 attachment_service_weak_ptr_factory_
.GetWeakPtr()) {
105 DCHECK(CalledOnValidThread());
106 DCHECK(attachment_service_
);
109 GenericChangeProcessor::~GenericChangeProcessor() {
110 DCHECK(CalledOnValidThread());
113 void GenericChangeProcessor::ApplyChangesFromSyncModel(
114 const syncer::BaseTransaction
* trans
,
116 const syncer::ImmutableChangeRecordList
& changes
) {
117 DCHECK(CalledOnValidThread());
118 DCHECK(syncer_changes_
.empty());
119 for (syncer::ChangeRecordList::const_iterator it
=
120 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
121 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
122 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
123 if (it
->specifics
.has_password()) {
124 DCHECK(it
->extra
.get());
125 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
126 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
127 CopyFrom(it
->extra
->unencrypted());
129 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
130 syncer_changes_
.push_back(
131 syncer::SyncChange(FROM_HERE
,
132 syncer::SyncChange::ACTION_DELETE
,
133 syncer::SyncData::CreateRemoteData(
135 specifics
? *specifics
: it
->specifics
,
137 empty_list_of_attachment_ids
,
138 attachment_service_proxy_
)));
140 syncer::SyncChange::SyncChangeType action
=
141 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
142 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
143 // Need to load specifics from node.
144 syncer::ReadNode
read_node(trans
);
145 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
146 error_handler()->OnSingleDatatypeUnrecoverableError(
148 "Failed to look up data for received change with id " +
149 base::Int64ToString(it
->id
));
152 syncer_changes_
.push_back(syncer::SyncChange(
155 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
160 void GenericChangeProcessor::CommitChangesFromSyncModel() {
161 DCHECK(CalledOnValidThread());
162 if (syncer_changes_
.empty())
164 if (!local_service_
.get()) {
165 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
166 syncer::SyncError
error(FROM_HERE
,
167 syncer::SyncError::DATATYPE_ERROR
,
168 "Local service destroyed.",
170 error_handler()->OnSingleDatatypeUnrecoverableError(error
.location(),
174 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
176 syncer_changes_
.clear();
178 error_handler()->OnSingleDatatypeUnrecoverableError(
179 error
.location(), error
.message());
183 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
184 syncer::ModelType type
) const {
185 // This is slow / memory intensive. Should be used sparingly by datatypes.
186 syncer::SyncDataList data
;
187 GetAllSyncDataReturnError(type
, &data
);
191 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
192 syncer::ModelType type
,
193 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
194 const std::string
& context
) {
195 DCHECK(syncer::ProtocolTypes().Has(type
));
197 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
198 return syncer::SyncError(FROM_HERE
,
199 syncer::SyncError::DATATYPE_ERROR
,
200 "Context size limit exceeded.",
204 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
205 trans
.SetDataTypeContext(type
, refresh_status
, context
);
207 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
208 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
210 return syncer::SyncError();
213 void GenericChangeProcessor::OnAttachmentUploaded(
214 const syncer::AttachmentId
& attachment_id
) {
215 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
216 trans
.UpdateEntriesWithAttachmentId(attachment_id
);
219 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
220 syncer::ModelType type
,
221 syncer::SyncDataList
* current_sync_data
) const {
222 DCHECK(CalledOnValidThread());
223 std::string type_name
= syncer::ModelTypeToString(type
);
224 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
225 syncer::ReadNode
root(&trans
);
226 if (root
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
227 syncer::BaseNode::INIT_OK
) {
228 syncer::SyncError
error(FROM_HERE
,
229 syncer::SyncError::DATATYPE_ERROR
,
230 "Server did not create the top-level " + type_name
+
231 " node. We might be running against an out-of-"
237 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
238 DCHECK_NE(type
, syncer::BOOKMARKS
);
240 std::vector
<int64
> child_ids
;
241 root
.GetChildIds(&child_ids
);
243 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
244 it
!= child_ids
.end(); ++it
) {
245 syncer::ReadNode
sync_child_node(&trans
);
246 if (sync_child_node
.InitByIdLookup(*it
) !=
247 syncer::BaseNode::INIT_OK
) {
248 syncer::SyncError
error(FROM_HERE
,
249 syncer::SyncError::DATATYPE_ERROR
,
250 "Failed to fetch child node for type " +
255 current_sync_data
->push_back(BuildRemoteSyncData(
256 sync_child_node
.GetId(), sync_child_node
, attachment_service_proxy_
));
258 return syncer::SyncError();
261 bool GenericChangeProcessor::GetDataTypeContext(syncer::ModelType type
,
262 std::string
* context
) const {
263 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
264 sync_pb::DataTypeContext context_proto
;
265 trans
.GetDataTypeContext(type
, &context_proto
);
266 if (!context_proto
.has_context())
270 syncer::GetModelTypeFromSpecificsFieldNumber(
271 context_proto
.data_type_id()));
272 *context
= context_proto
.context();
276 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type
) {
277 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
278 syncer::ReadNode
root(&trans
);
279 if (root
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
280 syncer::BaseNode::INIT_OK
)
283 // Subtract one to account for type's root node.
284 return root
.GetTotalNodeCount() - 1;
289 // TODO(isherman): Investigating http://crbug.com/121592
290 // WARNING: this code is sensitive to compiler optimizations. Be careful
291 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
292 // the compiler attempts to merge it with other calls, losing useful information
293 // in breakpad uploads.
294 syncer::SyncError
LogLookupFailure(
295 syncer::BaseNode::InitByLookupResult lookup_result
,
296 const tracked_objects::Location
& from_here
,
297 const std::string
& error_prefix
,
298 syncer::ModelType type
,
299 DataTypeErrorHandler
* error_handler
) {
300 switch (lookup_result
) {
301 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
302 syncer::SyncError error
;
303 error
.Reset(from_here
,
305 "could not find entry matching the lookup criteria.",
307 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
309 LOG(ERROR
) << "Delete: Bad entry.";
312 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
313 syncer::SyncError error
;
314 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
315 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
317 LOG(ERROR
) << "Delete: Deleted entry.";
320 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
321 syncer::SyncError error
;
322 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
323 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
325 LOG(ERROR
) << "Delete: Undecryptable entry.";
328 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
329 syncer::SyncError error
;
330 error
.Reset(from_here
,
331 error_prefix
+ "a precondition was not met for calling init.",
333 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
335 LOG(ERROR
) << "Delete: Failed precondition.";
339 syncer::SyncError error
;
340 // Should have listed all the possible error cases above.
341 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
342 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
344 LOG(ERROR
) << "Delete: Unknown error.";
350 syncer::SyncError
AttemptDelete(const syncer::SyncChange
& change
,
351 syncer::ModelType type
,
352 const std::string
& type_str
,
353 syncer::WriteNode
* node
,
354 DataTypeErrorHandler
* error_handler
) {
355 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
356 if (change
.sync_data().IsLocal()) {
357 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
359 syncer::SyncError
error(
361 syncer::SyncError::DATATYPE_ERROR
,
362 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
363 change
.location().ToString(),
365 error_handler
->OnSingleDatatypeUnrecoverableError(error
.location(),
371 syncer::BaseNode::InitByLookupResult result
=
372 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
373 if (result
!= syncer::BaseNode::INIT_OK
) {
374 return LogLookupFailure(
376 "Failed to delete " + type_str
+ " node. Local data. " +
377 change
.location().ToString(),
378 type
, error_handler
);
381 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
382 syncer::SyncDataRemote(change
.sync_data()).GetId());
383 if (result
!= syncer::BaseNode::INIT_OK
) {
384 return LogLookupFailure(
386 "Failed to delete " + type_str
+ " node. Non-local data. " +
387 change
.location().ToString(),
388 type
, error_handler
);
391 if (IsActOnceDataType(type
))
395 return syncer::SyncError();
398 // A callback invoked on completion of AttachmentService::StoreAttachment.
399 void IgnoreStoreResult(const syncer::AttachmentService::StoreResult
&) {
400 // TODO(maniscalco): Here is where we're going to update the in-directory
401 // entry to indicate that the attachments have been successfully stored on
402 // disk. Why do we care? Because we might crash after persisting the
403 // directory to disk, but before we have persisted its attachments, leaving us
404 // with danging attachment ids. Having a flag that indicates we've stored the
405 // entry will allow us to detect and filter entries with dangling attachment
409 void StoreAttachments(syncer::AttachmentService
* attachment_service
,
410 const syncer::AttachmentList
& attachments
) {
411 DCHECK(attachment_service
);
412 syncer::AttachmentService::StoreCallback ignore_store_result
=
413 base::Bind(&IgnoreStoreResult
);
414 attachment_service
->StoreAttachments(attachments
, ignore_store_result
);
419 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
420 const tracked_objects::Location
& from_here
,
421 const syncer::SyncChangeList
& list_of_changes
) {
422 DCHECK(CalledOnValidThread());
424 // Keep track of brand new attachments so we can persist them on this device
425 // and upload them to the server.
426 syncer::AttachmentList new_attachments
;
428 syncer::WriteTransaction
trans(from_here
, share_handle());
430 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
431 iter
!= list_of_changes
.end();
433 const syncer::SyncChange
& change
= *iter
;
434 DCHECK_NE(change
.sync_data().GetDataType(), syncer::UNSPECIFIED
);
435 syncer::ModelType type
= change
.sync_data().GetDataType();
436 std::string type_str
= syncer::ModelTypeToString(type
);
437 syncer::WriteNode
sync_node(&trans
);
438 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
439 syncer::SyncError error
=
440 AttemptDelete(change
, type
, type_str
, &sync_node
, error_handler());
445 if (merge_result_
.get()) {
446 merge_result_
->set_num_items_deleted(
447 merge_result_
->num_items_deleted() + 1);
449 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
450 syncer::SyncError error
= HandleActionAdd(
451 change
, type_str
, type
, trans
, &sync_node
, &new_attachments
);
455 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
456 syncer::SyncError error
= HandleActionUpdate(
457 change
, type_str
, type
, trans
, &sync_node
, &new_attachments
);
462 syncer::SyncError
error(
464 syncer::SyncError::DATATYPE_ERROR
,
465 "Received unset SyncChange in the change processor, " +
466 change
.location().ToString(),
468 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
471 LOG(ERROR
) << "Unset sync change.";
476 if (!new_attachments
.empty()) {
477 StoreAttachments(attachment_service_
.get(), new_attachments
);
480 return syncer::SyncError();
483 // WARNING: this code is sensitive to compiler optimizations. Be careful
484 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
485 // the compiler attempts to merge it with other calls, losing useful information
486 // in breakpad uploads.
487 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
488 const syncer::SyncChange
& change
,
489 const std::string
& type_str
,
490 const syncer::ModelType
& type
,
491 const syncer::WriteTransaction
& trans
,
492 syncer::WriteNode
* sync_node
,
493 syncer::AttachmentList
* 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
.InitByTagLookup(syncer::ModelTypeToRootTag(
499 sync_data_local
.GetDataType())) != 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(FROM_HERE
,
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(FROM_HERE
,
522 LOG(ERROR
) << "Create: Empty tag.";
525 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS
: {
526 syncer::SyncError error
;
527 error
.Reset(FROM_HERE
, error_prefix
+ "entry already exists", type
);
528 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
530 LOG(ERROR
) << "Create: Entry exists.";
533 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
534 syncer::SyncError error
;
535 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type
);
536 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
538 LOG(ERROR
) << "Create: Could not create entry.";
541 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
542 syncer::SyncError error
;
544 FROM_HERE
, error_prefix
+ "failed to set predecessor", type
);
545 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
547 LOG(ERROR
) << "Create: Bad predecessor.";
551 syncer::SyncError error
;
552 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type
);
553 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
555 LOG(ERROR
) << "Create: Unknown error.";
560 sync_node
->SetTitle(change
.sync_data().GetTitle());
561 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
563 syncer::AttachmentIdList attachment_ids
= sync_data_local
.GetAttachmentIds();
564 SetAttachmentMetadata(attachment_ids
, sync_node
);
566 // Return any newly added attachments.
567 const syncer::AttachmentList
& local_attachments_for_upload
=
568 sync_data_local
.GetLocalAttachmentsForUpload();
569 new_attachments
->insert(new_attachments
->end(),
570 local_attachments_for_upload
.begin(),
571 local_attachments_for_upload
.end());
573 if (merge_result_
.get()) {
574 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
576 return syncer::SyncError();
578 // WARNING: this code is sensitive to compiler optimizations. Be careful
579 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
580 // the compiler attempts to merge it with other calls, losing useful information
581 // in breakpad uploads.
582 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
583 const syncer::SyncChange
& change
,
584 const std::string
& type_str
,
585 const syncer::ModelType
& type
,
586 const syncer::WriteTransaction
& trans
,
587 syncer::WriteNode
* sync_node
,
588 syncer::AttachmentList
* new_attachments
) {
589 // TODO(zea): consider having this logic for all possible changes?
591 const syncer::SyncDataLocal
sync_data_local(change
.sync_data());
592 syncer::BaseNode::InitByLookupResult result
=
593 sync_node
->InitByClientTagLookup(sync_data_local
.GetDataType(),
594 sync_data_local
.GetTag());
595 if (result
!= syncer::BaseNode::INIT_OK
) {
596 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
597 change
.location().ToString() + ", ";
598 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
599 syncer::SyncError error
;
600 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type
);
601 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
603 LOG(ERROR
) << "Update: Empty tag.";
605 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
606 syncer::SyncError error
;
607 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type
);
608 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
610 LOG(ERROR
) << "Update: bad entry.";
612 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
613 syncer::SyncError error
;
614 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type
);
615 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
617 LOG(ERROR
) << "Update: deleted entry.";
620 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
621 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
622 const sync_pb::EntitySpecifics
& specifics
=
623 sync_node
->GetEntry()->GetSpecifics();
624 CHECK(specifics
.has_encrypted());
625 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
626 const bool agreement
= encrypted_types
.Has(type
);
627 if (!agreement
&& !can_decrypt
) {
628 syncer::SyncError error
;
629 error
.Reset(FROM_HERE
,
630 "Failed to load encrypted entry, missing key and "
631 "nigori mismatch for " +
634 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
636 LOG(ERROR
) << "Update: encr case 1.";
638 } else if (agreement
&& can_decrypt
) {
639 syncer::SyncError error
;
640 error
.Reset(FROM_HERE
,
641 "Failed to load encrypted entry, we have the key "
642 "and the nigori matches (?!) for " +
645 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
647 LOG(ERROR
) << "Update: encr case 2.";
649 } else if (agreement
) {
650 syncer::SyncError error
;
651 error
.Reset(FROM_HERE
,
652 "Failed to load encrypted entry, missing key and "
653 "the nigori matches for " +
656 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
658 LOG(ERROR
) << "Update: encr case 3.";
661 syncer::SyncError error
;
662 error
.Reset(FROM_HERE
,
663 "Failed to load encrypted entry, we have the key"
664 "(?!) and nigori mismatch for " +
667 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
669 LOG(ERROR
) << "Update: encr case 4.";
675 sync_node
->SetTitle(change
.sync_data().GetTitle());
676 SetNodeSpecifics(sync_data_local
.GetSpecifics(), sync_node
);
677 SetAttachmentMetadata(sync_data_local
.GetAttachmentIds(), sync_node
);
679 // Return any newly added attachments.
680 const syncer::AttachmentList
& local_attachments_for_upload
=
681 sync_data_local
.GetLocalAttachmentsForUpload();
682 new_attachments
->insert(new_attachments
->end(),
683 local_attachments_for_upload
.begin(),
684 local_attachments_for_upload
.end());
686 if (merge_result_
.get()) {
687 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
690 // TODO(sync): Support updating other parts of the sync node (title,
691 // successor, parent, etc.).
692 return syncer::SyncError();
695 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
696 syncer::ModelType type
,
698 DCHECK(CalledOnValidThread());
700 DCHECK_NE(type
, syncer::UNSPECIFIED
);
701 std::string type_name
= syncer::ModelTypeToString(type
);
702 std::string err_str
= "Server did not create the top-level " + type_name
+
703 " node. We might be running against an out-of-date server.";
705 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
706 syncer::ReadNode
type_root_node(&trans
);
707 if (type_root_node
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
708 syncer::BaseNode::INIT_OK
) {
709 LOG(ERROR
) << err_str
;
713 // The sync model has user created nodes if the type's root node has any
715 *has_nodes
= type_root_node
.HasChildren();
719 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type
) {
720 DCHECK(CalledOnValidThread());
721 DCHECK_NE(type
, syncer::UNSPECIFIED
);
722 // We only access the cryptographer while holding a transaction.
723 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
724 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
725 return !encrypted_types
.Has(type
) ||
726 trans
.GetCryptographer()->is_ready();
729 void GenericChangeProcessor::StartImpl() {
732 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
733 DCHECK(CalledOnValidThread());
734 return share_handle_
;
737 } // namespace browser_sync