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 "sync/api/sync_change.h"
11 #include "sync/api/sync_error.h"
12 #include "sync/api/syncable_service.h"
13 #include "sync/internal_api/public/base_node.h"
14 #include "sync/internal_api/public/change_record.h"
15 #include "sync/internal_api/public/read_node.h"
16 #include "sync/internal_api/public/read_transaction.h"
17 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
18 #include "sync/internal_api/public/write_node.h"
19 #include "sync/internal_api/public/write_transaction.h"
20 #include "sync/syncable/entry.h" // TODO(tim): Bug 123674.
22 namespace browser_sync
{
26 const int kContextSizeLimit
= 1024; // Datatype context size limit.
28 void SetNodeSpecifics(const sync_pb::EntitySpecifics
& entity_specifics
,
29 syncer::WriteNode
* write_node
) {
30 if (syncer::GetModelTypeFromSpecifics(entity_specifics
) ==
32 write_node
->SetPasswordSpecifics(
33 entity_specifics
.password().client_only_encrypted_data());
35 write_node
->SetEntitySpecifics(entity_specifics
);
39 syncer::SyncData
BuildRemoteSyncData(
41 const syncer::BaseNode
& read_node
,
42 const syncer::AttachmentServiceProxy
& attachment_service_proxy
) {
43 const syncer::AttachmentIdList
& attachment_ids
= read_node
.GetAttachmentIds();
44 // Use the specifics of non-password datatypes directly (encryption has
45 // already been handled).
46 if (read_node
.GetModelType() != syncer::PASSWORDS
) {
47 return syncer::SyncData::CreateRemoteData(sync_id
,
48 read_node
.GetEntitySpecifics(),
49 read_node
.GetModificationTime(),
51 attachment_service_proxy
);
54 // Passwords must be accessed differently, to account for their encryption,
55 // and stored into a temporary EntitySpecifics.
56 sync_pb::EntitySpecifics password_holder
;
57 password_holder
.mutable_password()->mutable_client_only_encrypted_data()->
58 CopyFrom(read_node
.GetPasswordSpecifics());
59 return syncer::SyncData::CreateRemoteData(sync_id
,
61 read_node
.GetModificationTime(),
63 attachment_service_proxy
);
68 GenericChangeProcessor::GenericChangeProcessor(
69 DataTypeErrorHandler
* error_handler
,
70 const base::WeakPtr
<syncer::SyncableService
>& local_service
,
71 const base::WeakPtr
<syncer::SyncMergeResult
>& merge_result
,
72 syncer::UserShare
* user_share
,
73 scoped_ptr
<syncer::AttachmentService
> attachment_service
)
74 : ChangeProcessor(error_handler
),
75 local_service_(local_service
),
76 merge_result_(merge_result
),
77 share_handle_(user_share
),
78 attachment_service_(attachment_service
.Pass()),
79 attachment_service_weak_ptr_factory_(attachment_service_
.get()),
80 attachment_service_proxy_(
81 base::MessageLoopProxy::current(),
82 attachment_service_weak_ptr_factory_
.GetWeakPtr()) {
83 DCHECK(CalledOnValidThread());
84 DCHECK(attachment_service_
);
87 GenericChangeProcessor::~GenericChangeProcessor() {
88 DCHECK(CalledOnValidThread());
91 void GenericChangeProcessor::ApplyChangesFromSyncModel(
92 const syncer::BaseTransaction
* trans
,
94 const syncer::ImmutableChangeRecordList
& changes
) {
95 DCHECK(CalledOnValidThread());
96 DCHECK(syncer_changes_
.empty());
97 for (syncer::ChangeRecordList::const_iterator it
=
98 changes
.Get().begin(); it
!= changes
.Get().end(); ++it
) {
99 if (it
->action
== syncer::ChangeRecord::ACTION_DELETE
) {
100 scoped_ptr
<sync_pb::EntitySpecifics
> specifics
;
101 if (it
->specifics
.has_password()) {
102 DCHECK(it
->extra
.get());
103 specifics
.reset(new sync_pb::EntitySpecifics(it
->specifics
));
104 specifics
->mutable_password()->mutable_client_only_encrypted_data()->
105 CopyFrom(it
->extra
->unencrypted());
107 const syncer::AttachmentIdList empty_list_of_attachment_ids
;
108 syncer_changes_
.push_back(
109 syncer::SyncChange(FROM_HERE
,
110 syncer::SyncChange::ACTION_DELETE
,
111 syncer::SyncData::CreateRemoteData(
113 specifics
? *specifics
: it
->specifics
,
115 empty_list_of_attachment_ids
,
116 attachment_service_proxy_
)));
118 syncer::SyncChange::SyncChangeType action
=
119 (it
->action
== syncer::ChangeRecord::ACTION_ADD
) ?
120 syncer::SyncChange::ACTION_ADD
: syncer::SyncChange::ACTION_UPDATE
;
121 // Need to load specifics from node.
122 syncer::ReadNode
read_node(trans
);
123 if (read_node
.InitByIdLookup(it
->id
) != syncer::BaseNode::INIT_OK
) {
124 error_handler()->OnSingleDatatypeUnrecoverableError(
126 "Failed to look up data for received change with id " +
127 base::Int64ToString(it
->id
));
130 syncer_changes_
.push_back(syncer::SyncChange(
133 BuildRemoteSyncData(it
->id
, read_node
, attachment_service_proxy_
)));
138 void GenericChangeProcessor::CommitChangesFromSyncModel() {
139 DCHECK(CalledOnValidThread());
140 if (syncer_changes_
.empty())
142 if (!local_service_
.get()) {
143 syncer::ModelType type
= syncer_changes_
[0].sync_data().GetDataType();
144 syncer::SyncError
error(FROM_HERE
,
145 syncer::SyncError::DATATYPE_ERROR
,
146 "Local service destroyed.",
148 error_handler()->OnSingleDatatypeUnrecoverableError(error
.location(),
152 syncer::SyncError error
= local_service_
->ProcessSyncChanges(FROM_HERE
,
154 syncer_changes_
.clear();
156 error_handler()->OnSingleDatatypeUnrecoverableError(
157 error
.location(), error
.message());
161 syncer::SyncDataList
GenericChangeProcessor::GetAllSyncData(
162 syncer::ModelType type
) const {
163 // This is slow / memory intensive. Should be used sparingly by datatypes.
164 syncer::SyncDataList data
;
165 GetAllSyncDataReturnError(type
, &data
);
169 syncer::SyncError
GenericChangeProcessor::UpdateDataTypeContext(
170 syncer::ModelType type
,
171 syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status
,
172 const std::string
& context
) {
173 DCHECK(syncer::ProtocolTypes().Has(type
));
175 if (context
.size() > static_cast<size_t>(kContextSizeLimit
)) {
176 return syncer::SyncError(FROM_HERE
,
177 syncer::SyncError::DATATYPE_ERROR
,
178 "Context size limit exceeded.",
182 syncer::WriteTransaction
trans(FROM_HERE
, share_handle());
183 trans
.SetDataTypeContext(type
, refresh_status
, context
);
185 // TODO(zea): plumb a pointer to the PSS or SyncManagerImpl here so we can
186 // trigger a datatype nudge if |refresh_status == REFRESH_NEEDED|.
188 return syncer::SyncError();
191 syncer::SyncError
GenericChangeProcessor::GetAllSyncDataReturnError(
192 syncer::ModelType type
,
193 syncer::SyncDataList
* current_sync_data
) const {
194 DCHECK(CalledOnValidThread());
195 std::string type_name
= syncer::ModelTypeToString(type
);
196 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
197 syncer::ReadNode
root(&trans
);
198 if (root
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
199 syncer::BaseNode::INIT_OK
) {
200 syncer::SyncError
error(FROM_HERE
,
201 syncer::SyncError::DATATYPE_ERROR
,
202 "Server did not create the top-level " + type_name
+
203 " node. We might be running against an out-of-"
209 // TODO(akalin): We'll have to do a tree traversal for bookmarks.
210 DCHECK_NE(type
, syncer::BOOKMARKS
);
212 std::vector
<int64
> child_ids
;
213 root
.GetChildIds(&child_ids
);
215 for (std::vector
<int64
>::iterator it
= child_ids
.begin();
216 it
!= child_ids
.end(); ++it
) {
217 syncer::ReadNode
sync_child_node(&trans
);
218 if (sync_child_node
.InitByIdLookup(*it
) !=
219 syncer::BaseNode::INIT_OK
) {
220 syncer::SyncError
error(FROM_HERE
,
221 syncer::SyncError::DATATYPE_ERROR
,
222 "Failed to fetch child node for type " +
227 current_sync_data
->push_back(BuildRemoteSyncData(
228 sync_child_node
.GetId(), sync_child_node
, attachment_service_proxy_
));
230 return syncer::SyncError();
233 bool GenericChangeProcessor::GetDataTypeContext(syncer::ModelType type
,
234 std::string
* context
) const {
235 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
236 sync_pb::DataTypeContext context_proto
;
237 trans
.GetDataTypeContext(type
, &context_proto
);
238 if (!context_proto
.has_context())
242 syncer::GetModelTypeFromSpecificsFieldNumber(
243 context_proto
.data_type_id()));
244 *context
= context_proto
.context();
248 int GenericChangeProcessor::GetSyncCountForType(syncer::ModelType type
) {
249 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
250 syncer::ReadNode
root(&trans
);
251 if (root
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
252 syncer::BaseNode::INIT_OK
)
255 // Subtract one to account for type's root node.
256 return root
.GetTotalNodeCount() - 1;
261 // TODO(isherman): Investigating http://crbug.com/121592
262 // WARNING: this code is sensitive to compiler optimizations. Be careful
263 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
264 // the compiler attempts to merge it with other calls, losing useful information
265 // in breakpad uploads.
266 syncer::SyncError
LogLookupFailure(
267 syncer::BaseNode::InitByLookupResult lookup_result
,
268 const tracked_objects::Location
& from_here
,
269 const std::string
& error_prefix
,
270 syncer::ModelType type
,
271 DataTypeErrorHandler
* error_handler
) {
272 switch (lookup_result
) {
273 case syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
: {
274 syncer::SyncError error
;
275 error
.Reset(from_here
,
277 "could not find entry matching the lookup criteria.",
279 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
281 LOG(ERROR
) << "Delete: Bad entry.";
284 case syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
: {
285 syncer::SyncError error
;
286 error
.Reset(from_here
, error_prefix
+ "entry is already deleted.", type
);
287 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
289 LOG(ERROR
) << "Delete: Deleted entry.";
292 case syncer::BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
: {
293 syncer::SyncError error
;
294 error
.Reset(from_here
, error_prefix
+ "unable to decrypt", type
);
295 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
297 LOG(ERROR
) << "Delete: Undecryptable entry.";
300 case syncer::BaseNode::INIT_FAILED_PRECONDITION
: {
301 syncer::SyncError error
;
302 error
.Reset(from_here
,
303 error_prefix
+ "a precondition was not met for calling init.",
305 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
307 LOG(ERROR
) << "Delete: Failed precondition.";
311 syncer::SyncError error
;
312 // Should have listed all the possible error cases above.
313 error
.Reset(from_here
, error_prefix
+ "unknown error", type
);
314 error_handler
->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
316 LOG(ERROR
) << "Delete: Unknown error.";
322 syncer::SyncError
AttemptDelete(
323 const syncer::SyncChange
& change
,
324 syncer::ModelType type
,
325 const std::string
& type_str
,
326 syncer::WriteNode
* node
,
327 DataTypeErrorHandler
* error_handler
) {
328 DCHECK_EQ(change
.change_type(), syncer::SyncChange::ACTION_DELETE
);
329 if (change
.sync_data().IsLocal()) {
330 const std::string
& tag
= syncer::SyncDataLocal(change
.sync_data()).GetTag();
332 syncer::SyncError
error(
334 syncer::SyncError::DATATYPE_ERROR
,
335 "Failed to delete " + type_str
+ " node. Local data, empty tag. " +
336 change
.location().ToString(),
338 error_handler
->OnSingleDatatypeUnrecoverableError(error
.location(),
344 syncer::BaseNode::InitByLookupResult result
=
345 node
->InitByClientTagLookup(change
.sync_data().GetDataType(), tag
);
346 if (result
!= syncer::BaseNode::INIT_OK
) {
347 return LogLookupFailure(
349 "Failed to delete " + type_str
+ " node. Local data. " +
350 change
.location().ToString(),
351 type
, error_handler
);
354 syncer::BaseNode::InitByLookupResult result
= node
->InitByIdLookup(
355 syncer::SyncDataRemote(change
.sync_data()).GetId());
356 if (result
!= syncer::BaseNode::INIT_OK
) {
357 return LogLookupFailure(
359 "Failed to delete " + type_str
+ " node. Non-local data. " +
360 change
.location().ToString(),
361 type
, error_handler
);
364 if (IsActOnceDataType(type
))
368 return syncer::SyncError();
373 syncer::SyncError
GenericChangeProcessor::ProcessSyncChanges(
374 const tracked_objects::Location
& from_here
,
375 const syncer::SyncChangeList
& list_of_changes
) {
376 DCHECK(CalledOnValidThread());
377 syncer::WriteTransaction
trans(from_here
, share_handle());
379 for (syncer::SyncChangeList::const_iterator iter
= list_of_changes
.begin();
380 iter
!= list_of_changes
.end();
382 const syncer::SyncChange
& change
= *iter
;
383 DCHECK_NE(change
.sync_data().GetDataType(), syncer::UNSPECIFIED
);
384 syncer::ModelType type
= change
.sync_data().GetDataType();
385 std::string type_str
= syncer::ModelTypeToString(type
);
386 syncer::WriteNode
sync_node(&trans
);
387 if (change
.change_type() == syncer::SyncChange::ACTION_DELETE
) {
388 syncer::SyncError error
=
389 AttemptDelete(change
, type
, type_str
, &sync_node
, error_handler());
394 attachment_service_
->OnSyncDataDelete(change
.sync_data());
395 if (merge_result_
.get()) {
396 merge_result_
->set_num_items_deleted(
397 merge_result_
->num_items_deleted() + 1);
399 } else if (change
.change_type() == syncer::SyncChange::ACTION_ADD
) {
400 syncer::SyncError error
=
401 HandleActionAdd(change
, type_str
, type
, trans
, &sync_node
);
405 } else if (change
.change_type() == syncer::SyncChange::ACTION_UPDATE
) {
406 syncer::SyncError error
=
407 HandleActionUpdate(change
, type_str
, type
, trans
, &sync_node
);
412 syncer::SyncError
error(
414 syncer::SyncError::DATATYPE_ERROR
,
415 "Received unset SyncChange in the change processor, " +
416 change
.location().ToString(),
418 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
421 LOG(ERROR
) << "Unset sync change.";
425 return syncer::SyncError();
428 // WARNING: this code is sensitive to compiler optimizations. Be careful
429 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
430 // the compiler attempts to merge it with other calls, losing useful information
431 // in breakpad uploads.
432 syncer::SyncError
GenericChangeProcessor::HandleActionAdd(
433 const syncer::SyncChange
& change
,
434 const std::string
& type_str
,
435 const syncer::ModelType
& type
,
436 const syncer::WriteTransaction
& trans
,
437 syncer::WriteNode
* sync_node
) {
438 // TODO(sync): Handle other types of creation (custom parents, folders,
440 syncer::ReadNode
root_node(&trans
);
441 if (root_node
.InitByTagLookup(syncer::ModelTypeToRootTag(
442 change
.sync_data().GetDataType())) != syncer::BaseNode::INIT_OK
) {
443 syncer::SyncError
error(FROM_HERE
,
444 syncer::SyncError::DATATYPE_ERROR
,
445 "Failed to look up root node for type " + type_str
,
447 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
450 LOG(ERROR
) << "Create: no root node.";
453 syncer::WriteNode::InitUniqueByCreationResult result
=
454 sync_node
->InitUniqueByCreation(
455 change
.sync_data().GetDataType(),
457 syncer::SyncDataLocal(change
.sync_data()).GetTag());
458 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
459 std::string error_prefix
= "Failed to create " + type_str
+ " node: " +
460 change
.location().ToString() + ", ";
462 case syncer::WriteNode::INIT_FAILED_EMPTY_TAG
: {
463 syncer::SyncError error
;
464 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type
);
465 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
467 LOG(ERROR
) << "Create: Empty tag.";
470 case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS
: {
471 syncer::SyncError error
;
472 error
.Reset(FROM_HERE
, error_prefix
+ "entry already exists", type
);
473 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
475 LOG(ERROR
) << "Create: Entry exists.";
478 case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY
: {
479 syncer::SyncError error
;
480 error
.Reset(FROM_HERE
, error_prefix
+ "failed to create entry", type
);
481 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
483 LOG(ERROR
) << "Create: Could not create entry.";
486 case syncer::WriteNode::INIT_FAILED_SET_PREDECESSOR
: {
487 syncer::SyncError error
;
489 FROM_HERE
, error_prefix
+ "failed to set predecessor", type
);
490 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
492 LOG(ERROR
) << "Create: Bad predecessor.";
496 syncer::SyncError error
;
497 error
.Reset(FROM_HERE
, error_prefix
+ "unknown error", type
);
498 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
500 LOG(ERROR
) << "Create: Unknown error.";
505 sync_node
->SetTitle(change
.sync_data().GetTitle());
506 SetNodeSpecifics(change
.sync_data().GetSpecifics(), sync_node
);
507 attachment_service_
->OnSyncDataAdd(change
.sync_data());
508 if (merge_result_
.get()) {
509 merge_result_
->set_num_items_added(merge_result_
->num_items_added() + 1);
511 return syncer::SyncError();
513 // WARNING: this code is sensitive to compiler optimizations. Be careful
514 // modifying any code around an OnSingleDatatypeUnrecoverableError call, else
515 // the compiler attempts to merge it with other calls, losing useful information
516 // in breakpad uploads.
517 syncer::SyncError
GenericChangeProcessor::HandleActionUpdate(
518 const syncer::SyncChange
& change
,
519 const std::string
& type_str
,
520 const syncer::ModelType
& type
,
521 const syncer::WriteTransaction
& trans
,
522 syncer::WriteNode
* sync_node
) {
523 // TODO(zea): consider having this logic for all possible changes?
524 syncer::BaseNode::InitByLookupResult result
=
525 sync_node
->InitByClientTagLookup(
526 change
.sync_data().GetDataType(),
527 syncer::SyncDataLocal(change
.sync_data()).GetTag());
528 if (result
!= syncer::BaseNode::INIT_OK
) {
529 std::string error_prefix
= "Failed to load " + type_str
+ " node. " +
530 change
.location().ToString() + ", ";
531 if (result
== syncer::BaseNode::INIT_FAILED_PRECONDITION
) {
532 syncer::SyncError error
;
533 error
.Reset(FROM_HERE
, error_prefix
+ "empty tag", type
);
534 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
536 LOG(ERROR
) << "Update: Empty tag.";
538 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
) {
539 syncer::SyncError error
;
540 error
.Reset(FROM_HERE
, error_prefix
+ "bad entry", type
);
541 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
543 LOG(ERROR
) << "Update: bad entry.";
545 } else if (result
== syncer::BaseNode::INIT_FAILED_ENTRY_IS_DEL
) {
546 syncer::SyncError error
;
547 error
.Reset(FROM_HERE
, error_prefix
+ "deleted entry", type
);
548 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
550 LOG(ERROR
) << "Update: deleted entry.";
553 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
554 syncer::ModelTypeSet
encrypted_types(trans
.GetEncryptedTypes());
555 const sync_pb::EntitySpecifics
& specifics
=
556 sync_node
->GetEntry()->GetSpecifics();
557 CHECK(specifics
.has_encrypted());
558 const bool can_decrypt
= crypto
->CanDecrypt(specifics
.encrypted());
559 const bool agreement
= encrypted_types
.Has(type
);
560 if (!agreement
&& !can_decrypt
) {
561 syncer::SyncError error
;
562 error
.Reset(FROM_HERE
,
563 "Failed to load encrypted entry, missing key and "
564 "nigori mismatch for " +
567 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
569 LOG(ERROR
) << "Update: encr case 1.";
571 } else if (agreement
&& can_decrypt
) {
572 syncer::SyncError error
;
573 error
.Reset(FROM_HERE
,
574 "Failed to load encrypted entry, we have the key "
575 "and the nigori matches (?!) for " +
578 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
580 LOG(ERROR
) << "Update: encr case 2.";
582 } else if (agreement
) {
583 syncer::SyncError error
;
584 error
.Reset(FROM_HERE
,
585 "Failed to load encrypted entry, missing key and "
586 "the nigori matches for " +
589 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
591 LOG(ERROR
) << "Update: encr case 3.";
594 syncer::SyncError error
;
595 error
.Reset(FROM_HERE
,
596 "Failed to load encrypted entry, we have the key"
597 "(?!) and nigori mismatch for " +
600 error_handler()->OnSingleDatatypeUnrecoverableError(FROM_HERE
,
602 LOG(ERROR
) << "Update: encr case 4.";
608 sync_node
->SetTitle(change
.sync_data().GetTitle());
609 SetNodeSpecifics(change
.sync_data().GetSpecifics(), sync_node
);
610 attachment_service_
->OnSyncDataUpdate(sync_node
->GetAttachmentIds(),
612 if (merge_result_
.get()) {
613 merge_result_
->set_num_items_modified(merge_result_
->num_items_modified() +
616 // TODO(sync): Support updating other parts of the sync node (title,
617 // successor, parent, etc.).
618 return syncer::SyncError();
621 bool GenericChangeProcessor::SyncModelHasUserCreatedNodes(
622 syncer::ModelType type
,
624 DCHECK(CalledOnValidThread());
626 DCHECK_NE(type
, syncer::UNSPECIFIED
);
627 std::string type_name
= syncer::ModelTypeToString(type
);
628 std::string err_str
= "Server did not create the top-level " + type_name
+
629 " node. We might be running against an out-of-date server.";
631 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
632 syncer::ReadNode
type_root_node(&trans
);
633 if (type_root_node
.InitByTagLookup(syncer::ModelTypeToRootTag(type
)) !=
634 syncer::BaseNode::INIT_OK
) {
635 LOG(ERROR
) << err_str
;
639 // The sync model has user created nodes if the type's root node has any
641 *has_nodes
= type_root_node
.HasChildren();
645 bool GenericChangeProcessor::CryptoReadyIfNecessary(syncer::ModelType type
) {
646 DCHECK(CalledOnValidThread());
647 DCHECK_NE(type
, syncer::UNSPECIFIED
);
648 // We only access the cryptographer while holding a transaction.
649 syncer::ReadTransaction
trans(FROM_HERE
, share_handle());
650 const syncer::ModelTypeSet encrypted_types
= trans
.GetEncryptedTypes();
651 return !encrypted_types
.Has(type
) ||
652 trans
.GetCryptographer()->is_ready();
655 void GenericChangeProcessor::StartImpl() {
656 DCHECK(CalledOnValidThread());
659 syncer::UserShare
* GenericChangeProcessor::share_handle() const {
660 DCHECK(CalledOnValidThread());
661 return share_handle_
;
664 } // namespace browser_sync