const char kAutofillEntryNamespaceTag[] = "autofill_entry|";
-// Merges timestamps from the |autofill| entry and |timestamps|. Returns
-// true if they were different, false if they were the same.
-// All of the timestamp vectors are assummed to be sorted, resulting vector is
-// sorted as well. Only two timestamps - the earliest and the latest are stored.
-bool MergeTimestamps(const sync_pb::AutofillSpecifics& autofill,
- const std::vector<base::Time>& timestamps,
- std::vector<base::Time>* new_timestamps) {
- DCHECK(new_timestamps);
-
- new_timestamps->clear();
- size_t timestamps_count = autofill.usage_timestamp_size();
- if (timestamps_count == 0 && timestamps.empty()) {
- return false;
- } else if (timestamps_count == 0) {
- new_timestamps->insert(new_timestamps->begin(),
- timestamps.begin(),
- timestamps.end());
- return true;
- } else if (timestamps.empty()) {
- new_timestamps->reserve(2);
- new_timestamps->push_back(base::Time::FromInternalValue(
- autofill.usage_timestamp(0)));
- if (timestamps_count > 1) {
- new_timestamps->push_back(base::Time::FromInternalValue(
- autofill.usage_timestamp(timestamps_count - 1)));
- }
+// Merges timestamps from the |sync_timestamps| and the |local_entry|.
+// Returns true if they were different, false if they were the same. If the
+// timestamps were different, fills |date_created| and |date_last_used| with the
+// merged timestamps. The |sync_timestamps| vector is assumed to be sorted.
+bool MergeTimestamps(
+ const google::protobuf::RepeatedField<int64_t>& sync_timestamps,
+ const AutofillEntry& local_entry,
+ base::Time* date_created,
+ base::Time* date_last_used) {
+ if (sync_timestamps.size() == 0) {
+ *date_created = local_entry.date_created();
+ *date_last_used = local_entry.date_last_used();
return true;
- } else {
- base::Time sync_time_begin = base::Time::FromInternalValue(
- autofill.usage_timestamp(0));
- base::Time sync_time_end = base::Time::FromInternalValue(
- autofill.usage_timestamp(timestamps_count - 1));
- if (timestamps.front() != sync_time_begin ||
- timestamps.back() != sync_time_end) {
- new_timestamps->push_back(
- timestamps.front() < sync_time_begin ? timestamps.front() :
- sync_time_begin);
- if (new_timestamps->back() != timestamps.back() ||
- new_timestamps->back() != sync_time_end) {
- new_timestamps->push_back(
- timestamps.back() > sync_time_end ? timestamps.back() :
- sync_time_end);
- }
- return true;
- } else {
- new_timestamps->insert(new_timestamps->begin(),
- timestamps.begin(),
- timestamps.end());
- return false;
- }
}
+
+ base::Time sync_date_created =
+ base::Time::FromInternalValue(*sync_timestamps.begin());
+ base::Time sync_date_last_used =
+ base::Time::FromInternalValue(*sync_timestamps.rbegin());
+
+ if (sync_date_created == local_entry.date_created() &&
+ sync_date_last_used == local_entry.date_last_used())
+ return false;
+
+ *date_created = std::min(local_entry.date_created(), sync_date_created);
+ *date_last_used = std::max(local_entry.date_last_used(), sync_date_last_used);
+ return true;
}
void* UserDataKey() {
AutocompleteSyncableService::AutocompleteSyncableService(
AutofillWebDataBackend* webdata_backend)
: webdata_backend_(webdata_backend),
- scoped_observer_(this),
- cull_expired_entries_(false) {
+ scoped_observer_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
DCHECK(webdata_backend_);
AutocompleteSyncableService::AutocompleteSyncableService()
: webdata_backend_(NULL),
- scoped_observer_(this),
- cull_expired_entries_(false) {
+ scoped_observer_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
}
scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
scoped_ptr<syncer::SyncErrorFactory> error_handler) {
DCHECK(CalledOnValidThread());
- DCHECK(!sync_processor_.get());
- DCHECK(sync_processor.get());
- DCHECK(error_handler.get());
- VLOG(1) << "Associating Autocomplete: MergeDataAndStartSyncing";
+ DCHECK(!sync_processor_);
+ DCHECK(sync_processor);
+ DCHECK(error_handler);
syncer::SyncMergeResult merge_result(type);
error_handler_ = error_handler.Pass();
if (!LoadAutofillData(&entries)) {
merge_result.set_error(error_handler_->CreateAndUploadError(
FROM_HERE,
- "Could not get the autocomplete data from WebDatabase."));
+ "Could not load autocomplete data from the WebDatabase."));
return merge_result;
}
// Go through and check for all the entries that sync already knows about.
// CreateOrUpdateEntry() will remove entries that are same with the synced
// ones from |new_db_entries|.
- for (syncer::SyncDataList::const_iterator sync_iter =
- initial_sync_data.begin();
- sync_iter != initial_sync_data.end(); ++sync_iter) {
- CreateOrUpdateEntry(*sync_iter, &new_db_entries, &new_synced_entries);
+ for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
+ it != initial_sync_data.end(); ++it) {
+ CreateOrUpdateEntry(*it, &new_db_entries, &new_synced_entries);
}
if (!SaveChangesToWebData(new_synced_entries)) {
webdata_backend_->NotifyOfMultipleAutofillChanges();
syncer::SyncChangeList new_changes;
- for (AutocompleteEntryMap::iterator i = new_db_entries.begin();
- i != new_db_entries.end(); ++i) {
+ for (AutocompleteEntryMap::iterator it = new_db_entries.begin();
+ it != new_db_entries.end(); ++it) {
new_changes.push_back(
syncer::SyncChange(FROM_HERE,
- i->second.first,
- CreateSyncData(*(i->second.second))));
- }
-
- if (cull_expired_entries_) {
- // This will schedule a deletion operation on the DB thread, which will
- // trigger a notification to propagate the deletion to Sync.
- webdata_backend_->RemoveExpiredFormElements();
+ it->second.first,
+ CreateSyncData(*(it->second.second))));
}
merge_result.set_error(
sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
+
+ // This will schedule a deletion operation on the DB thread, which will
+ // trigger a notification to propagate the deletion to Sync.
+ // NOTE: This must be called *after* the ProcessSyncChanges call above.
+ // Otherwise, an item that Sync is not yet aware of might expire, causing a
+ // Sync error when that item's deletion is propagated to Sync.
+ webdata_backend_->RemoveExpiredFormElements();
+
return merge_result;
}
syncer::SyncDataList AutocompleteSyncableService::GetAllSyncData(
syncer::ModelType type) const {
DCHECK(CalledOnValidThread());
- DCHECK(sync_processor_.get());
+ DCHECK(sync_processor_);
DCHECK_EQ(type, syncer::AUTOFILL);
syncer::SyncDataList current_data;
const tracked_objects::Location& from_here,
const syncer::SyncChangeList& change_list) {
DCHECK(CalledOnValidThread());
- DCHECK(sync_processor_.get());
+ DCHECK(sync_processor_);
- if (!sync_processor_.get()) {
+ if (!sync_processor_) {
syncer::SyncError error(FROM_HERE,
syncer::SyncError::DATATYPE_ERROR,
"Models not yet associated.",
switch (i->change_type()) {
case syncer::SyncChange::ACTION_ADD:
case syncer::SyncChange::ACTION_UPDATE:
- if (!db_entries.get()) {
+ if (!db_entries) {
if (!LoadAutofillData(&entries)) {
return error_handler_->CreateAndUploadError(
FROM_HERE,
}
CreateOrUpdateEntry(i->sync_data(), db_entries.get(), &new_entries);
break;
+
case syncer::SyncChange::ACTION_DELETE: {
DCHECK(i->sync_data().GetSpecifics().has_autofill())
<< "Autofill specifics data not present on delete!";
const sync_pb::AutofillSpecifics& autofill =
i->sync_data().GetSpecifics().autofill();
- if (autofill.has_value()) {
+ if (autofill.has_value())
list_processing_error = AutofillEntryDelete(autofill);
- } else {
- DLOG(WARNING)
- << "Delete for old-style autofill profile being dropped!";
- }
- } break;
+ else
+ VLOG(1) << "Delete for old-style autofill profile being dropped!";
+ break;
+ }
+
default:
- NOTREACHED() << "Unexpected sync change state.";
+ NOTREACHED();
return error_handler_->CreateAndUploadError(
FROM_HERE,
"ProcessSyncChanges failed on ChangeType " +
webdata_backend_->NotifyOfMultipleAutofillChanges();
- if (cull_expired_entries_) {
- // This will schedule a deletion operation on the DB thread, which will
- // trigger a notification to propagate the deletion to Sync.
- webdata_backend_->RemoveExpiredFormElements();
- }
+ // This will schedule a deletion operation on the DB thread, which will
+ // trigger a notification to propagate the deletion to Sync.
+ webdata_backend_->RemoveExpiredFormElements();
return list_processing_error;
}
void AutocompleteSyncableService::AutofillEntriesChanged(
const AutofillChangeList& changes) {
- // Check if sync is on. If we recieve this notification prior to sync being
+ // Check if sync is on. If we receive this notification prior to sync being
// started, we'll notify sync to start as soon as it can and later process
// all entries when MergeData..() is called. If we receive this notification
// sync has exited, it will be synced next time Chrome starts.
- if (sync_processor_.get()) {
+ if (sync_processor_) {
ActOnChanges(changes);
} else if (!flare_.is_null()) {
flare_.Run(syncer::AUTOFILL);
AutocompleteEntryMap* loaded_data,
std::vector<AutofillEntry>* new_entries) {
const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
- const sync_pb::AutofillSpecifics& autofill_specifics(
- specifics.autofill());
+ const sync_pb::AutofillSpecifics& autofill_specifics(specifics.autofill());
if (!autofill_specifics.has_value()) {
- DLOG(WARNING)
- << "Add/Update for old-style autofill profile being dropped!";
+ VLOG(1) << "Add/Update for old-style autofill profile being dropped!";
return;
}
AutofillKey key(autofill_specifics.name().c_str(),
autofill_specifics.value().c_str());
AutocompleteEntryMap::iterator it = loaded_data->find(key);
+ const google::protobuf::RepeatedField<int64_t>& timestamps =
+ autofill_specifics.usage_timestamp();
if (it == loaded_data->end()) {
// New entry.
- std::vector<base::Time> timestamps;
- size_t timestamps_count = autofill_specifics.usage_timestamp_size();
- timestamps.reserve(2);
- if (timestamps_count) {
- timestamps.push_back(base::Time::FromInternalValue(
- autofill_specifics.usage_timestamp(0)));
- }
- if (timestamps_count > 1) {
- timestamps.push_back(base::Time::FromInternalValue(
- autofill_specifics.usage_timestamp(timestamps_count - 1)));
+ base::Time date_created, date_last_used;
+ if (timestamps.size() > 0) {
+ date_created = base::Time::FromInternalValue(*timestamps.begin());
+ date_last_used = base::Time::FromInternalValue(*timestamps.rbegin());
}
- AutofillEntry new_entry(key, timestamps);
- new_entries->push_back(new_entry);
+ new_entries->push_back(AutofillEntry(key, date_created, date_last_used));
} else {
// Entry already present - merge if necessary.
- std::vector<base::Time> timestamps;
- bool different = MergeTimestamps(
- autofill_specifics, it->second.second->timestamps(), ×tamps);
+ base::Time date_created, date_last_used;
+ bool different = MergeTimestamps(timestamps, *it->second.second,
+ &date_created, &date_last_used);
if (different) {
- AutofillEntry new_entry(it->second.second->key(), timestamps);
+ AutofillEntry new_entry(
+ it->second.second->key(), date_created, date_last_used);
new_entries->push_back(new_entry);
- // Update the sync db if the list of timestamps have changed.
+ // Update the sync db since the timestamps have changed.
*(it->second.second) = new_entry;
it->second.first = syncer::SyncChange::ACTION_UPDATE;
} else {
autofill_specifics->mutable_autofill();
autofill->set_name(base::UTF16ToUTF8(entry.key().name()));
autofill->set_value(base::UTF16ToUTF8(entry.key().value()));
- const std::vector<base::Time>& ts(entry.timestamps());
- for (std::vector<base::Time>::const_iterator timestamp = ts.begin();
- timestamp != ts.end(); ++timestamp) {
- autofill->add_usage_timestamp(timestamp->ToInternalValue());
- }
+ autofill->add_usage_timestamp(entry.date_created().ToInternalValue());
+ if (entry.date_created() != entry.date_last_used())
+ autofill->add_usage_timestamp(entry.date_last_used().ToInternalValue());
}
syncer::SyncError AutocompleteSyncableService::AutofillEntryDelete(
void AutocompleteSyncableService::ActOnChanges(
const AutofillChangeList& changes) {
- DCHECK(sync_processor_.get());
+ DCHECK(sync_processor_);
syncer::SyncChangeList new_changes;
for (AutofillChangeList::const_iterator change = changes.begin();
change != changes.end(); ++change) {
switch (change->type()) {
case AutofillChange::ADD:
case AutofillChange::UPDATE: {
- std::vector<base::Time> timestamps;
+ base::Time date_created, date_last_used;
WebDatabase* db = webdata_backend_->GetDatabase();
if (!AutofillTable::FromWebDatabase(db)->GetAutofillTimestamps(
- change->key().name(),
- change->key().value(),
- ×tamps)) {
+ change->key().name(), change->key().value(),
+ &date_created, &date_last_used)) {
NOTREACHED();
return;
}
- AutofillEntry entry(change->key(), timestamps);
+ AutofillEntry entry(change->key(), date_created, date_last_used);
syncer::SyncChange::SyncChangeType change_type =
(change->type() == AutofillChange::ADD) ?
syncer::SyncChange::ACTION_ADD :
CreateSyncData(entry)));
break;
}
+
case AutofillChange::REMOVE: {
- std::vector<base::Time> timestamps;
- AutofillEntry entry(change->key(), timestamps);
+ AutofillEntry entry(change->key(), base::Time(), base::Time());
new_changes.push_back(
syncer::SyncChange(FROM_HERE,
syncer::SyncChange::ACTION_DELETE,
CreateSyncData(entry)));
break;
}
+
default:
NOTREACHED();
- break;
}
}
syncer::SyncError error =
sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
if (error.IsSet()) {
- DLOG(WARNING) << "[AUTOCOMPLETE SYNC]"
- << " Failed processing change:"
- << " Error:" << error.message();
+ VLOG(1) << "[AUTOCOMPLETE SYNC] Failed processing change. Error: "
+ << error.message();
}
}
-void AutocompleteSyncableService::UpdateCullSetting(
- bool cull_expired_entries) {
- DCHECK(CalledOnValidThread());
- cull_expired_entries_ = cull_expired_entries;
-}
-
syncer::SyncData AutocompleteSyncableService::CreateSyncData(
const AutofillEntry& entry) const {
sync_pb::EntitySpecifics autofill_specifics;
// static
std::string AutocompleteSyncableService::KeyToTag(const std::string& name,
const std::string& value) {
- std::string ns(kAutofillEntryNamespaceTag);
- return ns + net::EscapePath(name) + "|" + net::EscapePath(value);
+ std::string prefix(kAutofillEntryNamespaceTag);
+ return prefix + net::EscapePath(name) + "|" + net::EscapePath(value);
}