| Index: chrome/browser/sync/glue/autofill_model_associator.cc
|
| diff --git a/chrome/browser/sync/glue/autofill_model_associator.cc b/chrome/browser/sync/glue/autofill_model_associator.cc
|
| index 57d1baeb93641d197b1217e0037cdff7c9ac7a76..06d3427e2b343052072aca8055725046fb89b69b 100644
|
| --- a/chrome/browser/sync/glue/autofill_model_associator.cc
|
| +++ b/chrome/browser/sync/glue/autofill_model_associator.cc
|
| @@ -43,93 +43,100 @@ bool AutofillModelAssociator::AssociateModels() {
|
| return false;
|
| }
|
|
|
| - sync_api::WriteTransaction trans(
|
| - sync_service_->backend()->GetUserShareHandle());
|
| - sync_api::ReadNode autofill_root(&trans);
|
| - if (!autofill_root.InitByTagLookup(kAutofillTag)) {
|
| - error_handler_->OnUnrecoverableError();
|
| - LOG(ERROR) << "Server did not create the top-level autofill node. We "
|
| - << "might be running against an out-of-date server.";
|
| - return false;
|
| - }
|
| -
|
| std::set<AutofillKey> current_entries;
|
| std::vector<AutofillEntry> new_entries;
|
|
|
| - for (std::vector<AutofillEntry>::iterator ix = entries.begin();
|
| - ix != entries.end(); ++ix) {
|
| - if (id_map_.find(ix->key()) != id_map_.end()) {
|
| - // It seems that name/value pairs are not unique in the web database.
|
| - // As a result, we have to filter out duplicates here. This is probably
|
| - // a bug in the database.
|
| - continue;
|
| + {
|
| + sync_api::WriteTransaction trans(
|
| + sync_service_->backend()->GetUserShareHandle());
|
| + sync_api::ReadNode autofill_root(&trans);
|
| + if (!autofill_root.InitByTagLookup(kAutofillTag)) {
|
| + error_handler_->OnUnrecoverableError();
|
| + LOG(ERROR) << "Server did not create the top-level autofill node. We "
|
| + << "might be running against an out-of-date server.";
|
| + return false;
|
| }
|
|
|
| - std::string tag = KeyToTag(ix->key().name(), ix->key().value());
|
| -
|
| - sync_api::ReadNode node(&trans);
|
| - if (node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
|
| - const sync_pb::AutofillSpecifics& autofill(node.GetAutofillSpecifics());
|
| - DCHECK_EQ(tag, KeyToTag(UTF8ToUTF16(autofill.name()),
|
| - UTF8ToUTF16(autofill.value())));
|
| + for (std::vector<AutofillEntry>::iterator ix = entries.begin();
|
| + ix != entries.end(); ++ix) {
|
| + if (id_map_.find(ix->key()) != id_map_.end()) {
|
| + // It seems that name/value pairs are not unique in the web database.
|
| + // As a result, we have to filter out duplicates here. This is probably
|
| + // a bug in the database.
|
| + continue;
|
| + }
|
|
|
| - std::vector<base::Time> timestamps;
|
| - if (MergeTimestamps(autofill, ix->timestamps(), ×tamps)) {
|
| - AutofillEntry new_entry(ix->key(), timestamps);
|
| - new_entries.push_back(new_entry);
|
| + std::string tag = KeyToTag(ix->key().name(), ix->key().value());
|
| +
|
| + sync_api::ReadNode node(&trans);
|
| + if (node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
|
| + const sync_pb::AutofillSpecifics& autofill(node.GetAutofillSpecifics());
|
| + DCHECK_EQ(tag, KeyToTag(UTF8ToUTF16(autofill.name()),
|
| + UTF8ToUTF16(autofill.value())));
|
| +
|
| + std::vector<base::Time> timestamps;
|
| + if (MergeTimestamps(autofill, ix->timestamps(), ×tamps)) {
|
| + AutofillEntry new_entry(ix->key(), timestamps);
|
| + new_entries.push_back(new_entry);
|
| +
|
| + sync_api::WriteNode write_node(&trans);
|
| + if (!write_node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
|
| + LOG(ERROR) << "Failed to write autofill sync node.";
|
| + return false;
|
| + }
|
| + AutofillChangeProcessor::WriteAutofill(&write_node, new_entry);
|
| + }
|
|
|
| - sync_api::WriteNode write_node(&trans);
|
| - if (!write_node.InitByClientTagLookup(syncable::AUTOFILL, tag)) {
|
| - LOG(ERROR) << "Failed to write autofill sync node.";
|
| + Associate(&(ix->key()), node.GetId());
|
| + } else {
|
| + sync_api::WriteNode node(&trans);
|
| + if (!node.InitUniqueByCreation(syncable::AUTOFILL,
|
| + autofill_root, tag)) {
|
| + LOG(ERROR) << "Failed to create autofill sync node.";
|
| error_handler_->OnUnrecoverableError();
|
| return false;
|
| }
|
| - AutofillChangeProcessor::WriteAutofill(&write_node, new_entry);
|
| + node.SetTitle(UTF16ToWide(ix->key().name() + ix->key().value()));
|
| + AutofillChangeProcessor::WriteAutofill(&node, *ix);
|
| + Associate(&(ix->key()), node.GetId());
|
| }
|
|
|
| - Associate(&(ix->key()), node.GetId());
|
| - } else {
|
| - sync_api::WriteNode node(&trans);
|
| - if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) {
|
| - LOG(ERROR) << "Failed to create autofill sync node.";
|
| + current_entries.insert(ix->key());
|
| + }
|
| +
|
| + int64 sync_child_id = autofill_root.GetFirstChildId();
|
| + while (sync_child_id != sync_api::kInvalidId) {
|
| + sync_api::ReadNode sync_child_node(&trans);
|
| + if (!sync_child_node.InitByIdLookup(sync_child_id)) {
|
| + LOG(ERROR) << "Failed to fetch child node.";
|
| error_handler_->OnUnrecoverableError();
|
| return false;
|
| }
|
| - node.SetTitle(UTF16ToWide(ix->key().name() + ix->key().value()));
|
| - AutofillChangeProcessor::WriteAutofill(&node, *ix);
|
| - Associate(&(ix->key()), node.GetId());
|
| - }
|
| -
|
| - current_entries.insert(ix->key());
|
| - }
|
| -
|
| - int64 sync_child_id = autofill_root.GetFirstChildId();
|
| - while (sync_child_id != sync_api::kInvalidId) {
|
| - sync_api::ReadNode sync_child_node(&trans);
|
| - if (!sync_child_node.InitByIdLookup(sync_child_id)) {
|
| - LOG(ERROR) << "Failed to fetch child node.";
|
| - error_handler_->OnUnrecoverableError();
|
| - return false;
|
| - }
|
| - const sync_pb::AutofillSpecifics& autofill(
|
| - sync_child_node.GetAutofillSpecifics());
|
| - AutofillKey key(UTF8ToUTF16(autofill.name()),
|
| - UTF8ToUTF16(autofill.value()));
|
| -
|
| - if (current_entries.find(key) == current_entries.end()) {
|
| - std::vector<base::Time> timestamps;
|
| - int timestamps_count = autofill.usage_timestamp_size();
|
| - for (int c = 0; c < timestamps_count; ++c) {
|
| - timestamps.push_back(base::Time::FromInternalValue(
|
| - autofill.usage_timestamp(c)));
|
| + const sync_pb::AutofillSpecifics& autofill(
|
| + sync_child_node.GetAutofillSpecifics());
|
| + AutofillKey key(UTF8ToUTF16(autofill.name()),
|
| + UTF8ToUTF16(autofill.value()));
|
| +
|
| + if (current_entries.find(key) == current_entries.end()) {
|
| + std::vector<base::Time> timestamps;
|
| + int timestamps_count = autofill.usage_timestamp_size();
|
| + for (int c = 0; c < timestamps_count; ++c) {
|
| + timestamps.push_back(base::Time::FromInternalValue(
|
| + autofill.usage_timestamp(c)));
|
| + }
|
| + Associate(&key, sync_child_node.GetId());
|
| + new_entries.push_back(AutofillEntry(key, timestamps));
|
| }
|
| - Associate(&key, sync_child_node.GetId());
|
| - new_entries.push_back(AutofillEntry(key, timestamps));
|
| - }
|
|
|
| - sync_child_id = sync_child_node.GetSuccessorId();
|
| + sync_child_id = sync_child_node.GetSuccessorId();
|
| + }
|
| }
|
|
|
| + // Since we're on the DB thread, we don't have to worry about updating
|
| + // the autofill database after closing the write transaction, since
|
| + // this is the only thread that writes to the database. We also don't have
|
| + // to worry about the sync model getting out of sync, because changes are
|
| + // propogated to the ChangeProcessor on this thread.
|
| if (new_entries.size() &&
|
| !web_database_->UpdateAutofillEntries(new_entries)) {
|
| LOG(ERROR) << "Failed to update autofill entries.";
|
|
|