Index: chrome/browser/extensions/api/storage/syncable_settings_storage.cc |
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc |
index d25bd170c3ef1e61dd9bbf92d4c92c86d927c456..71db3f5c9847f3521dcd1301164da8b1c3d14396 100644 |
--- a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc |
+++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc |
@@ -12,10 +12,10 @@ |
#include "sync/api/sync_data.h" |
#include "sync/protocol/extension_setting_specifics.pb.h" |
-namespace extensions { |
- |
using content::BrowserThread; |
+namespace extensions { |
+ |
SyncableSettingsStorage::SyncableSettingsStorage( |
const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >& |
observers, |
@@ -164,102 +164,97 @@ void SyncableSettingsStorage::SyncResultIfEnabled( |
// Sync-related methods. |
syncer::SyncError SyncableSettingsStorage::StartSyncing( |
- const base::DictionaryValue& sync_state, |
+ scoped_ptr<base::DictionaryValue> sync_state, |
scoped_ptr<SettingsSyncProcessor> sync_processor) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
+ DCHECK(sync_state); |
DCHECK(!sync_processor_.get()); |
sync_processor_ = sync_processor.Pass(); |
- sync_processor_->Init(sync_state); |
+ sync_processor_->Init(*sync_state); |
ReadResult maybe_settings = delegate_->Get(); |
if (maybe_settings->HasError()) { |
return syncer::SyncError( |
- FROM_HERE, |
- syncer::SyncError::DATATYPE_ERROR, |
+ FROM_HERE, syncer::SyncError::DATATYPE_ERROR, |
base::StringPrintf("Failed to get settings: %s", |
- maybe_settings->error().message.c_str()), |
+ maybe_settings->error().message.c_str()), |
sync_processor_->type()); |
} |
- const base::DictionaryValue& settings = maybe_settings->settings(); |
- return sync_state.empty() ? |
- SendLocalSettingsToSync(settings) : |
- OverwriteLocalSettingsWithSync(sync_state, settings); |
+ scoped_ptr<base::DictionaryValue> current_settings = |
+ maybe_settings->PassSettings(); |
+ return sync_state->empty() ? SendLocalSettingsToSync(current_settings.Pass()) |
+ : OverwriteLocalSettingsWithSync( |
+ sync_state.Pass(), current_settings.Pass()); |
} |
syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync( |
- const base::DictionaryValue& settings) { |
+ scoped_ptr<base::DictionaryValue> local_state) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
+ if (local_state->empty()) |
+ return syncer::SyncError(); |
+ |
+ // Transform the current settings into a list of sync changes. |
ValueStoreChangeList changes; |
- for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) { |
- changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy())); |
+ while (!local_state->empty()) { |
+ // It's not possible to iterate over a DictionaryValue and modify it at the |
+ // same time, so hack around that restriction. |
+ std::string key = base::DictionaryValue::Iterator(*local_state).key(); |
+ scoped_ptr<base::Value> value; |
+ local_state->RemoveWithoutPathExpansion(key, &value); |
+ changes.push_back(ValueStoreChange(key, nullptr, value.release())); |
} |
- if (changes.empty()) |
- return syncer::SyncError(); |
- |
syncer::SyncError error = sync_processor_->SendChanges(changes); |
if (error.IsSet()) |
StopSyncing(); |
- |
return error; |
} |
syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync( |
- const base::DictionaryValue& sync_state, |
- const base::DictionaryValue& settings) { |
+ scoped_ptr<base::DictionaryValue> sync_state, |
+ scoped_ptr<base::DictionaryValue> local_state) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- // Treat this as a list of changes to sync and use ProcessSyncChanges. |
- // This gives notifications etc for free. |
- scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy()); |
+ // This is implemented by building up a list of sync changes then sending |
+ // those to ProcessSyncChanges. This generates events like onStorageChanged. |
+ scoped_ptr<SettingSyncDataList> changes(new SettingSyncDataList()); |
- SettingSyncDataList changes; |
- for (base::DictionaryValue::Iterator it(settings); |
- !it.IsAtEnd(); it.Advance()) { |
+ for (base::DictionaryValue::Iterator it(*local_state); !it.IsAtEnd(); |
+ it.Advance()) { |
scoped_ptr<base::Value> sync_value; |
- if (new_sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) { |
+ if (sync_state->RemoveWithoutPathExpansion(it.key(), &sync_value)) { |
if (sync_value->Equals(&it.value())) { |
// Sync and local values are the same, no changes to send. |
} else { |
// Sync value is different, update local setting with new value. |
- changes.push_back( |
- SettingSyncData( |
- syncer::SyncChange::ACTION_UPDATE, |
- extension_id_, |
- it.key(), |
- sync_value.Pass())); |
+ changes->push_back( |
+ new SettingSyncData(syncer::SyncChange::ACTION_UPDATE, |
+ extension_id_, it.key(), sync_value.Pass())); |
} |
} else { |
// Not synced, delete local setting. |
- changes.push_back( |
- SettingSyncData( |
- syncer::SyncChange::ACTION_DELETE, |
- extension_id_, |
- it.key(), |
- scoped_ptr<base::Value>(new base::DictionaryValue()))); |
+ changes->push_back(new SettingSyncData( |
+ syncer::SyncChange::ACTION_DELETE, extension_id_, it.key(), |
+ scoped_ptr<base::Value>(new base::DictionaryValue()))); |
} |
} |
// Add all new settings to local settings. |
- while (!new_sync_state->empty()) { |
- base::DictionaryValue::Iterator first_entry(*new_sync_state); |
- std::string key = first_entry.key(); |
+ while (!sync_state->empty()) { |
+ // It's not possible to iterate over a DictionaryValue and modify it at the |
+ // same time, so hack around that restriction. |
+ std::string key = base::DictionaryValue::Iterator(*sync_state).key(); |
scoped_ptr<base::Value> value; |
- CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value)); |
- changes.push_back( |
- SettingSyncData( |
- syncer::SyncChange::ACTION_ADD, |
- extension_id_, |
- key, |
- value.Pass())); |
+ CHECK(sync_state->RemoveWithoutPathExpansion(key, &value)); |
+ changes->push_back(new SettingSyncData(syncer::SyncChange::ACTION_ADD, |
+ extension_id_, key, value.Pass())); |
} |
- if (changes.empty()) |
+ if (changes->empty()) |
return syncer::SyncError(); |
- |
- return ProcessSyncChanges(changes); |
+ return ProcessSyncChanges(changes.Pass()); |
} |
void SyncableSettingsStorage::StopSyncing() { |
@@ -268,9 +263,9 @@ void SyncableSettingsStorage::StopSyncing() { |
} |
syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( |
- const SettingSyncDataList& sync_changes) { |
+ scoped_ptr<SettingSyncDataList> sync_changes) { |
DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- DCHECK(!sync_changes.empty()) << "No sync changes for " << extension_id_; |
+ DCHECK(!sync_changes->empty()) << "No sync changes for " << extension_id_; |
if (!sync_processor_.get()) { |
return syncer::SyncError( |
@@ -283,16 +278,15 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( |
std::vector<syncer::SyncError> errors; |
ValueStoreChangeList changes; |
- for (SettingSyncDataList::const_iterator it = sync_changes.begin(); |
- it != sync_changes.end(); ++it) { |
- DCHECK_EQ(extension_id_, it->extension_id()); |
- |
- const std::string& key = it->key(); |
- const base::Value& value = it->value(); |
+ for (SettingSyncDataList::iterator it = sync_changes->begin(); |
+ it != sync_changes->end(); ++it) { |
+ DCHECK_EQ(extension_id_, (*it)->extension_id()); |
+ const std::string& key = (*it)->key(); |
+ scoped_ptr<base::Value> change_value = (*it)->PassValue(); |
scoped_ptr<base::Value> current_value; |
{ |
- ReadResult maybe_settings = Get(it->key()); |
+ ReadResult maybe_settings = Get(key); |
if (maybe_settings->HasError()) { |
errors.push_back(syncer::SyncError( |
FROM_HERE, |
@@ -309,29 +303,29 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( |
syncer::SyncError error; |
- switch (it->change_type()) { |
+ switch ((*it)->change_type()) { |
case syncer::SyncChange::ACTION_ADD: |
if (!current_value.get()) { |
- error = OnSyncAdd(key, value.DeepCopy(), &changes); |
+ error = OnSyncAdd(key, change_value.release(), &changes); |
} else { |
// Already a value; hopefully a local change has beaten sync in a |
- // race and it's not a bug, so pretend it's an update. |
+ // race and change's not a bug, so pretend change's an update. |
LOG(WARNING) << "Got add from sync for existing setting " << |
extension_id_ << "/" << key; |
- error = OnSyncUpdate( |
- key, current_value.release(), value.DeepCopy(), &changes); |
+ error = OnSyncUpdate(key, current_value.release(), |
+ change_value.release(), &changes); |
} |
break; |
case syncer::SyncChange::ACTION_UPDATE: |
if (current_value.get()) { |
- error = OnSyncUpdate( |
- key, current_value.release(), value.DeepCopy(), &changes); |
+ error = OnSyncUpdate(key, current_value.release(), |
+ change_value.release(), &changes); |
} else { |
- // Similarly, pretend it's an add. |
+ // Similarly, pretend change's an add. |
LOG(WARNING) << "Got update from sync for nonexistent setting" << |
extension_id_ << "/" << key; |
- error = OnSyncAdd(key, value.DeepCopy(), &changes); |
+ error = OnSyncAdd(key, change_value.release(), &changes); |
} |
break; |
@@ -339,7 +333,7 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( |
if (current_value.get()) { |
error = OnSyncDelete(key, current_value.release(), &changes); |
} else { |
- // Similarly, ignore it. |
+ // Similarly, ignore change. |
LOG(WARNING) << "Got delete from sync for nonexistent setting " << |
extension_id_ << "/" << key; |
} |