Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor.cc
blob2c97b3e44ce2f7d794192d9abc1f05bc164fc7d6
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 {
25 namespace {
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) ==
32 syncer::PASSWORDS) {
33 write_node->SetPasswordSpecifics(
34 entity_specifics.password().client_only_encrypted_data());
35 } else {
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();
45 return record;
48 // Replace |write_nodes|'s attachment ids with |attachment_ids|.
49 void SetAttachmentMetadata(const syncer::AttachmentIdList& attachment_ids,
50 syncer::WriteNode* write_node) {
51 DCHECK(write_node);
52 sync_pb::AttachmentMetadata attachment_metadata;
53 std::transform(
54 attachment_ids.begin(),
55 attachment_ids.end(),
56 RepeatedFieldBackInserter(attachment_metadata.mutable_record()),
57 AttachmentIdToRecord);
58 write_node->SetAttachmentMetadata(attachment_metadata);
61 syncer::SyncData BuildRemoteSyncData(
62 int64 sync_id,
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(),
72 attachment_ids,
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,
82 password_holder,
83 read_node.GetModificationTime(),
84 attachment_ids,
85 attachment_service_proxy);
88 } // namespace
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 const scoped_refptr<syncer::AttachmentStore>& attachment_store)
98 : ChangeProcessor(error_handler),
99 type_(type),
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.get()) {
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, *user_share, store_birthday, this);
114 attachment_service_weak_ptr_factory_.reset(
115 new base::WeakPtrFactory<syncer::AttachmentService>(
116 attachment_service_.get()));
117 attachment_service_proxy_.reset(new syncer::AttachmentServiceProxy(
118 base::MessageLoopProxy::current(),
119 attachment_service_weak_ptr_factory_->GetWeakPtr()));
120 UploadAllAttachmentsNotOnServer();
121 } else {
122 attachment_service_proxy_.reset(new 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,
134 int64 model_version,
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(
150 syncer::SyncChange(FROM_HERE,
151 syncer::SyncChange::ACTION_DELETE,
152 syncer::SyncData::CreateRemoteData(
153 it->id,
154 specifics ? *specifics : it->specifics,
155 base::Time(),
156 empty_list_of_attachment_ids,
157 *attachment_service_proxy_)));
158 } else {
159 syncer::SyncChange::SyncChangeType action =
160 (it->action == syncer::ChangeRecord::ACTION_ADD) ?
161 syncer::SyncChange::ACTION_ADD : syncer::SyncChange::ACTION_UPDATE;
162 // Need to load specifics from node.
163 syncer::ReadNode read_node(trans);
164 if (read_node.InitByIdLookup(it->id) != syncer::BaseNode::INIT_OK) {
165 syncer::SyncError error(
166 FROM_HERE,
167 syncer::SyncError::DATATYPE_ERROR,
168 "Failed to look up data for received change with id " +
169 base::Int64ToString(it->id),
170 syncer::GetModelTypeFromSpecifics(it->specifics));
171 error_handler()->OnSingleDataTypeUnrecoverableError(error);
172 return;
174 syncer_changes_.push_back(syncer::SyncChange(
175 FROM_HERE,
176 action,
177 BuildRemoteSyncData(it->id, read_node, *attachment_service_proxy_)));
182 void GenericChangeProcessor::CommitChangesFromSyncModel() {
183 DCHECK(CalledOnValidThread());
184 if (syncer_changes_.empty())
185 return;
186 if (!local_service_.get()) {
187 syncer::ModelType type = syncer_changes_[0].sync_data().GetDataType();
188 syncer::SyncError error(FROM_HERE,
189 syncer::SyncError::DATATYPE_ERROR,
190 "Local service destroyed.",
191 type);
192 error_handler()->OnSingleDataTypeUnrecoverableError(error);
193 return;
195 syncer::SyncError error = local_service_->ProcessSyncChanges(FROM_HERE,
196 syncer_changes_);
197 syncer_changes_.clear();
198 if (error.IsSet())
199 error_handler()->OnSingleDataTypeUnrecoverableError(error);
202 syncer::SyncDataList GenericChangeProcessor::GetAllSyncData(
203 syncer::ModelType type) const {
204 DCHECK_EQ(type_, type);
205 // This is slow / memory intensive. Should be used sparingly by datatypes.
206 syncer::SyncDataList data;
207 GetAllSyncDataReturnError(&data);
208 return data;
211 syncer::SyncError GenericChangeProcessor::UpdateDataTypeContext(
212 syncer::ModelType type,
213 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
214 const std::string& context) {
215 DCHECK(syncer::ProtocolTypes().Has(type));
216 DCHECK_EQ(type_, type);
218 if (context.size() > static_cast<size_t>(kContextSizeLimit)) {
219 return syncer::SyncError(FROM_HERE,
220 syncer::SyncError::DATATYPE_ERROR,
221 "Context size limit exceeded.",
222 type);
225 syncer::WriteTransaction trans(FROM_HERE, share_handle());
226 trans.SetDataTypeContext(type, refresh_status, context);
228 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
229 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
231 return syncer::SyncError();
234 void GenericChangeProcessor::OnAttachmentUploaded(
235 const syncer::AttachmentId& attachment_id) {
236 syncer::WriteTransaction trans(FROM_HERE, share_handle());
237 trans.UpdateEntriesMarkAttachmentAsOnServer(attachment_id);
240 syncer::SyncError GenericChangeProcessor::GetAllSyncDataReturnError(
241 syncer::SyncDataList* current_sync_data) const {
242 DCHECK(CalledOnValidThread());
243 std::string type_name = syncer::ModelTypeToString(type_);
244 syncer::ReadTransaction trans(FROM_HERE, share_handle());
245 syncer::ReadNode root(&trans);
246 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
247 syncer::SyncError error(FROM_HERE,
248 syncer::SyncError::DATATYPE_ERROR,
249 "Server did not create the top-level " + type_name +
250 " node. We might be running against an out-of-"
251 "date server.",
252 type_);
253 return error;
256 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
257 DCHECK_NE(type_, syncer::BOOKMARKS);
259 std::vector<int64> child_ids;
260 root.GetChildIds(&child_ids);
262 for (std::vector<int64>::iterator it = child_ids.begin();
263 it != child_ids.end(); ++it) {
264 syncer::ReadNode sync_child_node(&trans);
265 if (sync_child_node.InitByIdLookup(*it) !=
266 syncer::BaseNode::INIT_OK) {
267 syncer::SyncError error(
268 FROM_HERE,
269 syncer::SyncError::DATATYPE_ERROR,
270 "Failed to fetch child node for type " + type_name + ".",
271 type_);
272 return error;
274 current_sync_data->push_back(BuildRemoteSyncData(
275 sync_child_node.GetId(), sync_child_node, *attachment_service_proxy_));
277 return syncer::SyncError();
280 bool GenericChangeProcessor::GetDataTypeContext(std::string* context) const {
281 syncer::ReadTransaction trans(FROM_HERE, share_handle());
282 sync_pb::DataTypeContext context_proto;
283 trans.GetDataTypeContext(type_, &context_proto);
284 if (!context_proto.has_context())
285 return false;
287 DCHECK_EQ(type_,
288 syncer::GetModelTypeFromSpecificsFieldNumber(
289 context_proto.data_type_id()));
290 *context = context_proto.context();
291 return true;
294 int GenericChangeProcessor::GetSyncCount() {
295 syncer::ReadTransaction trans(FROM_HERE, share_handle());
296 syncer::ReadNode root(&trans);
297 if (root.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK)
298 return 0;
300 // Subtract one to account for type's root node.
301 return root.GetTotalNodeCount() - 1;
304 namespace {
306 // WARNING: this code is sensitive to compiler optimizations. Be careful
307 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
308 // the compiler attempts to merge it with other calls, losing useful information
309 // in breakpad uploads.
310 syncer::SyncError LogLookupFailure(
311 syncer::BaseNode::InitByLookupResult lookup_result,
312 const tracked_objects::Location& from_here,
313 const std::string& error_prefix,
314 syncer::ModelType type,
315 DataTypeErrorHandler* error_handler) {
316 switch (lookup_result) {
317 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD: {
318 syncer::SyncError error;
319 error.Reset(from_here,
320 error_prefix +
321 "could not find entry matching the lookup criteria.",
322 type);
323 error_handler->OnSingleDataTypeUnrecoverableError(error);
324 LOG(ERROR) << "Delete: Bad entry.";
325 return error;
327 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL: {
328 syncer::SyncError error;
329 error.Reset(from_here, error_prefix + "entry is already deleted.", type);
330 error_handler->OnSingleDataTypeUnrecoverableError(error);
331 LOG(ERROR) << "Delete: Deleted entry.";
332 return error;
334 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY: {
335 syncer::SyncError error;
336 error.Reset(from_here, error_prefix + "unable to decrypt", type);
337 error_handler->OnSingleDataTypeUnrecoverableError(error);
338 LOG(ERROR) << "Delete: Undecryptable entry.";
339 return error;
341 case syncer::BaseNode::INIT_FAILED_PRECONDITION: {
342 syncer::SyncError error;
343 error.Reset(from_here,
344 error_prefix + "a precondition was not met for calling init.",
345 type);
346 error_handler->OnSingleDataTypeUnrecoverableError(error);
347 LOG(ERROR) << "Delete: Failed precondition.";
348 return error;
350 default: {
351 syncer::SyncError error;
352 // Should have listed all the possible error cases above.
353 error.Reset(from_here, error_prefix + "unknown error", type);
354 error_handler->OnSingleDataTypeUnrecoverableError(error);
355 LOG(ERROR) << "Delete: Unknown error.";
356 return error;
361 syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
362 syncer::ModelType type,
363 const std::string& type_str,
364 syncer::WriteNode* node,
365 DataTypeErrorHandler* error_handler) {
366 DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
367 if (change.sync_data().IsLocal()) {
368 const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
369 if (tag.empty()) {
370 syncer::SyncError error(
371 FROM_HERE,
372 syncer::SyncError::DATATYPE_ERROR,
373 "Failed to delete " + type_str + " node. Local data, empty tag. " +
374 change.location().ToString(),
375 type);
376 error_handler->OnSingleDataTypeUnrecoverableError(error);
377 NOTREACHED();
378 return error;
381 syncer::BaseNode::InitByLookupResult result =
382 node->InitByClientTagLookup(change.sync_data().GetDataType(), tag);
383 if (result != syncer::BaseNode::INIT_OK) {
384 return LogLookupFailure(
385 result, FROM_HERE,
386 "Failed to delete " + type_str + " node. Local data. " +
387 change.location().ToString(),
388 type, error_handler);
390 } else {
391 syncer::BaseNode::InitByLookupResult result = node->InitByIdLookup(
392 syncer::SyncDataRemote(change.sync_data()).GetId());
393 if (result != syncer::BaseNode::INIT_OK) {
394 return LogLookupFailure(
395 result, FROM_HERE,
396 "Failed to delete " + type_str + " node. Non-local data. " +
397 change.location().ToString(),
398 type, error_handler);
401 if (IsActOnceDataType(type))
402 node->Drop();
403 else
404 node->Tombstone();
405 return syncer::SyncError();
408 } // namespace
410 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
411 const tracked_objects::Location& from_here,
412 const syncer::SyncChangeList& list_of_changes) {
413 DCHECK(CalledOnValidThread());
415 // Keep track of brand new attachments so we can persist them on this device
416 // and upload them to the server.
417 syncer::AttachmentIdSet new_attachments;
419 syncer::WriteTransaction trans(from_here, share_handle());
421 for (syncer::SyncChangeList::const_iterator iter = list_of_changes.begin();
422 iter != list_of_changes.end();
423 ++iter) {
424 const syncer::SyncChange& change = *iter;
425 DCHECK_EQ(change.sync_data().GetDataType(), type_);
426 std::string type_str = syncer::ModelTypeToString(type_);
427 syncer::WriteNode sync_node(&trans);
428 if (change.change_type() == syncer::SyncChange::ACTION_DELETE) {
429 syncer::SyncError error =
430 AttemptDelete(change, type_, type_str, &sync_node, error_handler());
431 if (error.IsSet()) {
432 NOTREACHED();
433 return error;
435 if (merge_result_.get()) {
436 merge_result_->set_num_items_deleted(
437 merge_result_->num_items_deleted() + 1);
439 } else if (change.change_type() == syncer::SyncChange::ACTION_ADD) {
440 syncer::SyncError error = HandleActionAdd(
441 change, type_str, trans, &sync_node, &new_attachments);
442 if (error.IsSet()) {
443 return error;
445 } else if (change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
446 syncer::SyncError error = HandleActionUpdate(
447 change, type_str, trans, &sync_node, &new_attachments);
448 if (error.IsSet()) {
449 return error;
451 } else {
452 syncer::SyncError error(
453 FROM_HERE,
454 syncer::SyncError::DATATYPE_ERROR,
455 "Received unset SyncChange in the change processor, " +
456 change.location().ToString(),
457 type_);
458 error_handler()->OnSingleDataTypeUnrecoverableError(error);
459 NOTREACHED();
460 LOG(ERROR) << "Unset sync change.";
461 return error;
465 if (!new_attachments.empty()) {
466 // If datatype uses attachments it should have supplied attachment store
467 // which would initialize attachment_service_. Fail if it isn't so.
468 if (!attachment_service_.get()) {
469 syncer::SyncError error(
470 FROM_HERE,
471 syncer::SyncError::DATATYPE_ERROR,
472 "Datatype performs attachment operation without initializing "
473 "attachment store",
474 type_);
475 error_handler()->OnSingleDataTypeUnrecoverableError(error);
476 NOTREACHED();
477 return error;
479 attachment_service_->UploadAttachments(new_attachments);
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,
496 // etc.).
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,
504 type_);
505 error_handler()->OnSingleDataTypeUnrecoverableError(error);
506 NOTREACHED();
507 LOG(ERROR) << "Create: no root node.";
508 return error;
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() + ", ";
516 switch (result) {
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.";
522 return error;
524 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
525 syncer::SyncError error;
526 error.Reset(FROM_HERE, error_prefix + "entry already exists", type_);
527 error_handler()->OnSingleDataTypeUnrecoverableError(error);
528 LOG(ERROR) << "Create: Entry exists.";
529 return error;
531 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
532 syncer::SyncError error;
533 error.Reset(FROM_HERE, error_prefix + "failed to create entry", type_);
534 error_handler()->OnSingleDataTypeUnrecoverableError(error);
535 LOG(ERROR) << "Create: Could not create entry.";
536 return error;
538 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR: {
539 syncer::SyncError error;
540 error.Reset(
541 FROM_HERE, error_prefix + "failed to set predecessor", type_);
542 error_handler()->OnSingleDataTypeUnrecoverableError(error);
543 LOG(ERROR) << "Create: Bad predecessor.";
544 return error;
546 default: {
547 syncer::SyncError error;
548 error.Reset(FROM_HERE, error_prefix + "unknown error", type_);
549 error_handler()->OnSingleDataTypeUnrecoverableError(error);
550 LOG(ERROR) << "Create: Unknown error.";
551 return error;
555 sync_node->SetTitle(change.sync_data().GetTitle());
556 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
558 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
559 SetAttachmentMetadata(attachment_ids, sync_node);
561 // Return any newly added attachments.
562 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
563 if (merge_result_.get()) {
564 merge_result_->set_num_items_added(merge_result_->num_items_added() + 1);
566 return syncer::SyncError();
568 // WARNING: this code is sensitive to compiler optimizations. Be careful
569 // modifying any code around an OnSingleDataTypeUnrecoverableError call, else
570 // the compiler attempts to merge it with other calls, losing useful information
571 // in breakpad uploads.
572 syncer::SyncError GenericChangeProcessor::HandleActionUpdate(
573 const syncer::SyncChange& change,
574 const std::string& type_str,
575 const syncer::WriteTransaction& trans,
576 syncer::WriteNode* sync_node,
577 syncer::AttachmentIdSet* new_attachments) {
578 // TODO(zea): consider having this logic for all possible changes?
580 const syncer::SyncDataLocal sync_data_local(change.sync_data());
581 syncer::BaseNode::InitByLookupResult result =
582 sync_node->InitByClientTagLookup(sync_data_local.GetDataType(),
583 sync_data_local.GetTag());
584 if (result != syncer::BaseNode::INIT_OK) {
585 std::string error_prefix = "Failed to load " + type_str + " node. " +
586 change.location().ToString() + ", ";
587 if (result == syncer::BaseNode::INIT_FAILED_PRECONDITION) {
588 syncer::SyncError error;
589 error.Reset(FROM_HERE, error_prefix + "empty tag", type_);
590 error_handler()->OnSingleDataTypeUnrecoverableError(error);
591 LOG(ERROR) << "Update: Empty tag.";
592 return error;
593 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD) {
594 syncer::SyncError error;
595 error.Reset(FROM_HERE, error_prefix + "bad entry", type_);
596 error_handler()->OnSingleDataTypeUnrecoverableError(error);
597 LOG(ERROR) << "Update: bad entry.";
598 return error;
599 } else if (result == syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL) {
600 syncer::SyncError error;
601 error.Reset(FROM_HERE, error_prefix + "deleted entry", type_);
602 error_handler()->OnSingleDataTypeUnrecoverableError(error);
603 LOG(ERROR) << "Update: deleted entry.";
604 return error;
605 } else {
606 syncer::Cryptographer* crypto = trans.GetCryptographer();
607 syncer::ModelTypeSet encrypted_types(trans.GetEncryptedTypes());
608 const sync_pb::EntitySpecifics& specifics =
609 sync_node->GetEntry()->GetSpecifics();
610 CHECK(specifics.has_encrypted());
611 const bool can_decrypt = crypto->CanDecrypt(specifics.encrypted());
612 const bool agreement = encrypted_types.Has(type_);
613 if (!agreement && !can_decrypt) {
614 syncer::SyncError error;
615 error.Reset(FROM_HERE,
616 "Failed to load encrypted entry, missing key and "
617 "nigori mismatch for " +
618 type_str + ".",
619 type_);
620 error_handler()->OnSingleDataTypeUnrecoverableError(error);
621 LOG(ERROR) << "Update: encr case 1.";
622 return error;
623 } else if (agreement && can_decrypt) {
624 syncer::SyncError error;
625 error.Reset(FROM_HERE,
626 "Failed to load encrypted entry, we have the key "
627 "and the nigori matches (?!) for " +
628 type_str + ".",
629 type_);
630 error_handler()->OnSingleDataTypeUnrecoverableError(error);
631 LOG(ERROR) << "Update: encr case 2.";
632 return error;
633 } else if (agreement) {
634 syncer::SyncError error;
635 error.Reset(FROM_HERE,
636 "Failed to load encrypted entry, missing key and "
637 "the nigori matches for " +
638 type_str + ".",
639 type_);
640 error_handler()->OnSingleDataTypeUnrecoverableError(error);
641 LOG(ERROR) << "Update: encr case 3.";
642 return error;
643 } else {
644 syncer::SyncError error;
645 error.Reset(FROM_HERE,
646 "Failed to load encrypted entry, we have the key"
647 "(?!) and nigori mismatch for " +
648 type_str + ".",
649 type_);
650 error_handler()->OnSingleDataTypeUnrecoverableError(error);
651 LOG(ERROR) << "Update: encr case 4.";
652 return error;
657 sync_node->SetTitle(change.sync_data().GetTitle());
658 SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
659 syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
660 SetAttachmentMetadata(attachment_ids, sync_node);
662 // Return any newly added attachments.
663 new_attachments->insert(attachment_ids.begin(), attachment_ids.end());
665 if (merge_result_.get()) {
666 merge_result_->set_num_items_modified(merge_result_->num_items_modified() +
669 // TODO(sync): Support updating other parts of the sync node (title,
670 // successor, parent, etc.).
671 return syncer::SyncError();
674 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
675 DCHECK(CalledOnValidThread());
676 DCHECK(has_nodes);
677 std::string type_name = syncer::ModelTypeToString(type_);
678 std::string err_str = "Server did not create the top-level " + type_name +
679 " node. We might be running against an out-of-date server.";
680 *has_nodes = false;
681 syncer::ReadTransaction trans(FROM_HERE, share_handle());
682 syncer::ReadNode type_root_node(&trans);
683 if (type_root_node.InitTypeRoot(type_) != syncer::BaseNode::INIT_OK) {
684 LOG(ERROR) << err_str;
685 return false;
688 // The sync model has user created nodes if the type's root node has any
689 // children.
690 *has_nodes = type_root_node.HasChildren();
691 return true;
694 bool GenericChangeProcessor::CryptoReadyIfNecessary() {
695 DCHECK(CalledOnValidThread());
696 // We only access the cryptographer while holding a transaction.
697 syncer::ReadTransaction trans(FROM_HERE, share_handle());
698 const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes();
699 return !encrypted_types.Has(type_) || trans.GetCryptographer()->is_ready();
702 void GenericChangeProcessor::StartImpl() {
705 syncer::UserShare* GenericChangeProcessor::share_handle() const {
706 DCHECK(CalledOnValidThread());
707 return share_handle_;
710 void GenericChangeProcessor::UploadAllAttachmentsNotOnServer() {
711 DCHECK(CalledOnValidThread());
712 DCHECK(attachment_service_.get());
713 syncer::AttachmentIdSet id_set;
715 syncer::ReadTransaction trans(FROM_HERE, share_handle());
716 trans.GetAttachmentIdsToUpload(type_, &id_set);
718 if (!id_set.empty()) {
719 attachment_service_->UploadAttachments(id_set);
723 } // namespace sync_driver