Commit 6387496e authored by kalman's avatar kalman Committed by Commit bot

Remove a bunch of DeepCopy() calls in the chrome.storage API.

DeepCopy() is expensive and we're doing a lot of it, transferring ownership is
better. I also tidied up some code here and there, like C++11 niceties,
removing unnecessary linked_ptrs, and better commenting.

R=rdevlin.cronin@chromium.org

Review URL: https://codereview.chromium.org/1141963002

Cr-Commit-Position: refs/heads/master@{#330597}
parent 8707fef0
...@@ -13,90 +13,51 @@ ...@@ -13,90 +13,51 @@
namespace extensions { namespace extensions {
SettingSyncData::SettingSyncData( SettingSyncData::SettingSyncData(const syncer::SyncChange& sync_change)
const syncer::SyncChange& sync_change) { : change_type_(sync_change.change_type()) {
Init(sync_change.change_type(), sync_change.sync_data()); ExtractSyncData(sync_change.sync_data());
} }
SettingSyncData::SettingSyncData( SettingSyncData::SettingSyncData(const syncer::SyncData& sync_data)
const syncer::SyncData& sync_data) { : change_type_(syncer::SyncChange::ACTION_INVALID) {
Init(syncer::SyncChange::ACTION_INVALID, sync_data); ExtractSyncData(sync_data);
} }
void SettingSyncData::Init( SettingSyncData::SettingSyncData(syncer::SyncChange::SyncChangeType change_type,
syncer::SyncChange::SyncChangeType change_type, const std::string& extension_id,
const syncer::SyncData& sync_data) { const std::string& key,
DCHECK(!internal_.get()); scoped_ptr<base::Value> value)
sync_pb::EntitySpecifics specifics = sync_data.GetSpecifics(); : change_type_(change_type),
// The data must only be either extension or app specfics. extension_id_(extension_id),
DCHECK_NE(specifics.has_extension_setting(), key_(key),
specifics.has_app_setting()); value_(value.Pass()) {
if (specifics.has_extension_setting()) {
InitFromExtensionSettingSpecifics(
change_type,
specifics.extension_setting());
} else if (specifics.has_app_setting()) {
InitFromExtensionSettingSpecifics(
change_type,
specifics.app_setting().extension_setting());
}
}
void SettingSyncData::InitFromExtensionSettingSpecifics(
syncer::SyncChange::SyncChangeType change_type,
const sync_pb::ExtensionSettingSpecifics& specifics) {
DCHECK(!internal_.get());
scoped_ptr<base::Value> value(
base::JSONReader::Read(specifics.value()));
if (!value.get()) {
LOG(WARNING) << "Specifics for " << specifics.extension_id() << "/" <<
specifics.key() << " had bad JSON for value: " << specifics.value();
value.reset(new base::DictionaryValue());
}
internal_ = new Internal(
change_type,
specifics.extension_id(),
specifics.key(),
value.Pass());
} }
SettingSyncData::SettingSyncData(
syncer::SyncChange::SyncChangeType change_type,
const std::string& extension_id,
const std::string& key,
scoped_ptr<base::Value> value)
: internal_(new Internal(change_type, extension_id, key, value.Pass())) {}
SettingSyncData::~SettingSyncData() {} SettingSyncData::~SettingSyncData() {}
syncer::SyncChange::SyncChangeType SettingSyncData::change_type() const { scoped_ptr<base::Value> SettingSyncData::PassValue() {
return internal_->change_type_; DCHECK(value_) << "value has already been Pass()ed";
} return value_.Pass();
const std::string& SettingSyncData::extension_id() const {
return internal_->extension_id_;
} }
const std::string& SettingSyncData::key() const { void SettingSyncData::ExtractSyncData(const syncer::SyncData& sync_data) {
return internal_->key_; sync_pb::EntitySpecifics specifics = sync_data.GetSpecifics();
} // The specifics are exclusively either extension or app settings.
DCHECK_NE(specifics.has_extension_setting(), specifics.has_app_setting());
const base::Value& SettingSyncData::value() const { const sync_pb::ExtensionSettingSpecifics& extension_specifics =
return *internal_->value_; specifics.has_extension_setting()
} ? specifics.extension_setting()
: specifics.app_setting().extension_setting();
SettingSyncData::Internal::Internal(
syncer::SyncChange::SyncChangeType change_type, extension_id_ = extension_specifics.extension_id();
const std::string& extension_id, key_ = extension_specifics.key();
const std::string& key, value_.reset(base::JSONReader::Read(extension_specifics.value()));
scoped_ptr<base::Value> value)
: change_type_(change_type), if (!value_) {
extension_id_(extension_id), LOG(WARNING) << "Specifics for " << extension_id_ << "/" << key_
key_(key), << " had bad JSON for value: " << extension_specifics.value();
value_(value.Pass()) { value_.reset(new base::DictionaryValue());
DCHECK(value_.get()); }
} }
SettingSyncData::Internal::~Internal() {}
} // namespace extensions } // namespace extensions
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTING_SYNC_DATA_H_ #ifndef CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTING_SYNC_DATA_H_
#define CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTING_SYNC_DATA_H_ #define CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTING_SYNC_DATA_H_
#include "base/memory/ref_counted.h" #include <string>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/values.h" #include "base/values.h"
#include "sync/api/sync_change.h" #include "sync/api/sync_change.h"
...@@ -39,52 +42,34 @@ class SettingSyncData { ...@@ -39,52 +42,34 @@ class SettingSyncData {
~SettingSyncData(); ~SettingSyncData();
// Returns the type of the sync change; may be ACTION_INVALID. // May return ACTION_INVALID if this object represents sync data that isn't
syncer::SyncChange::SyncChangeType change_type() const; // associated with a sync operation.
syncer::SyncChange::SyncChangeType change_type() const {
// Returns the extension id the setting is for. return change_type_;
const std::string& extension_id() const; }
const std::string& extension_id() const { return extension_id_; }
// Returns the settings key. const std::string& key() const { return key_; }
const std::string& key() const; // value() cannot be called if PassValue() has been called.
const base::Value& value() const { return *value_; }
// Returns the value of the setting. // Releases ownership of the value to the caller. Neither value() nor
const base::Value& value() const; // PassValue() can be after this.
scoped_ptr<base::Value> PassValue();
private: private:
// Ref-counted container for the data. // Populates the extension ID, key, and value from |sync_data|. This will be
// TODO(kalman): Use browser_sync::Immutable<Internal>. // either an extension or app settings data type.
class Internal : public base::RefCountedThreadSafe<Internal> { void ExtractSyncData(const syncer::SyncData& sync_data);
public:
Internal(
syncer::SyncChange::SyncChangeType change_type,
const std::string& extension_id,
const std::string& key,
scoped_ptr<base::Value> value);
syncer::SyncChange::SyncChangeType change_type_;
std::string extension_id_;
std::string key_;
scoped_ptr<base::Value> value_;
private:
friend class base::RefCountedThreadSafe<Internal>;
~Internal();
};
// Initializes internal_ from sync data for an extension or app setting. syncer::SyncChange::SyncChangeType change_type_;
void Init(syncer::SyncChange::SyncChangeType change_type, std::string extension_id_;
const syncer::SyncData& sync_data); std::string key_;
scoped_ptr<base::Value> value_;
// Initializes internal_ from extension specifics.
void InitFromExtensionSettingSpecifics(
syncer::SyncChange::SyncChangeType change_type,
const sync_pb::ExtensionSettingSpecifics& specifics);
scoped_refptr<Internal> internal_; DISALLOW_COPY_AND_ASSIGN(SettingSyncData);
}; };
typedef std::vector<SettingSyncData> SettingSyncDataList; typedef ScopedVector<SettingSyncData> SettingSyncDataList;
} // namespace extensions } // namespace extensions
......
...@@ -28,6 +28,10 @@ void AddAllSyncData(const std::string& extension_id, ...@@ -28,6 +28,10 @@ void AddAllSyncData(const std::string& extension_id,
} }
} }
scoped_ptr<base::DictionaryValue> EmptyDictionaryValue() {
return make_scoped_ptr(new base::DictionaryValue());
}
} // namespace } // namespace
SyncStorageBackend::SyncStorageBackend( SyncStorageBackend::SyncStorageBackend(
...@@ -52,13 +56,12 @@ SyncStorageBackend::~SyncStorageBackend() {} ...@@ -52,13 +56,12 @@ SyncStorageBackend::~SyncStorageBackend() {}
ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) { ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK_CURRENTLY_ON(BrowserThread::FILE);
base::DictionaryValue empty; return GetOrCreateStorageWithSyncData(extension_id, EmptyDictionaryValue());
return GetOrCreateStorageWithSyncData(extension_id, empty);
} }
SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData(
const std::string& extension_id, const std::string& extension_id,
const base::DictionaryValue& sync_data) const { scoped_ptr<base::DictionaryValue> sync_data) const {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK_CURRENTLY_ON(BrowserThread::FILE);
StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
...@@ -79,9 +82,9 @@ SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( ...@@ -79,9 +82,9 @@ SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData(
if (sync_processor_.get()) { if (sync_processor_.get()) {
syncer::SyncError error = syncable_storage->StartSyncing( syncer::SyncError error = syncable_storage->StartSyncing(
sync_data, CreateSettingsSyncProcessor(extension_id).Pass()); sync_data.Pass(), CreateSettingsSyncProcessor(extension_id).Pass());
if (error.IsSet()) if (error.IsSet())
syncable_storage.get()->StopSyncing(); syncable_storage->StopSyncing();
} }
return syncable_storage.get(); return syncable_storage.get();
} }
...@@ -110,10 +113,8 @@ std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const { ...@@ -110,10 +113,8 @@ std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const {
// Storage areas can be in-memory as well as on disk. |storage_objs_| will // Storage areas can be in-memory as well as on disk. |storage_objs_| will
// contain all that are in-memory. // contain all that are in-memory.
for (StorageObjMap::iterator it = storage_objs_.begin(); for (const auto& storage_obj : storage_objs_) {
it != storage_objs_.end(); result.insert(storage_obj.first);
++it) {
result.insert(it->first);
} }
// Leveldb databases are directories inside |base_path_|. // Leveldb databases are directories inside |base_path_|.
...@@ -148,7 +149,7 @@ syncer::SyncDataList SyncStorageBackend::GetAllSyncData(syncer::ModelType type) ...@@ -148,7 +149,7 @@ syncer::SyncDataList SyncStorageBackend::GetAllSyncData(syncer::ModelType type)
it != known_extension_ids.end(); it != known_extension_ids.end();
++it) { ++it) {
ValueStore::ReadResult maybe_settings = ValueStore::ReadResult maybe_settings =
GetOrCreateStorageWithSyncData(*it, base::DictionaryValue())->Get(); GetOrCreateStorageWithSyncData(*it, EmptyDictionaryValue())->Get();
if (maybe_settings->HasError()) { if (maybe_settings->HasError()) {
LOG(WARNING) << "Failed to get settings for " << *it << ": " LOG(WARNING) << "Failed to get settings for " << *it << ": "
<< maybe_settings->error().message; << maybe_settings->error().message;
...@@ -175,54 +176,50 @@ syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing( ...@@ -175,54 +176,50 @@ syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing(
sync_error_factory_ = sync_error_factory.Pass(); sync_error_factory_ = sync_error_factory.Pass();
// Group the initial sync data by extension id. // Group the initial sync data by extension id.
std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data; // The raw pointers are safe because ownership of each item is passed to
for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); // storage->StartSyncing or GetOrCreateStorageWithSyncData.
it != initial_sync_data.end(); std::map<std::string, base::DictionaryValue*> grouped_sync_data;
++it) {
SettingSyncData data(*it); for (const syncer::SyncData& sync_data : initial_sync_data) {
linked_ptr<base::DictionaryValue> sync_data = SettingSyncData data(sync_data);
grouped_sync_data[data.extension_id()]; // Yes this really is a reference to a pointer.
if (!sync_data.get()) { base::DictionaryValue*& settings = grouped_sync_data[data.extension_id()];
sync_data = if (!settings)
linked_ptr<base::DictionaryValue>(new base::DictionaryValue()); settings = new base::DictionaryValue();
grouped_sync_data[data.extension_id()] = sync_data; DCHECK(!settings->HasKey(data.key())) << "Duplicate settings for "
} << data.extension_id() << "/"
DCHECK(!sync_data->HasKey(data.key())) << "Duplicate settings for " << data.key();
<< data.extension_id() << "/" settings->SetWithoutPathExpansion(data.key(), data.PassValue());
<< data.key();
sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy());
} }
// Start syncing all existing storage areas. Any storage areas created in // Start syncing all existing storage areas. Any storage areas created in
// the future will start being synced as part of the creation process. // the future will start being synced as part of the creation process.
for (StorageObjMap::iterator it = storage_objs_.begin(); for (const auto& storage_obj : storage_objs_) {
it != storage_objs_.end(); const std::string& extension_id = storage_obj.first;
++it) { SyncableSettingsStorage* storage = storage_obj.second.get();
std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator
maybe_sync_data = grouped_sync_data.find(it->first); auto group = grouped_sync_data.find(extension_id);
syncer::SyncError error; syncer::SyncError error;
if (maybe_sync_data != grouped_sync_data.end()) { if (group != grouped_sync_data.end()) {
error = it->second->StartSyncing( error = storage->StartSyncing(
*maybe_sync_data->second, make_scoped_ptr(group->second),
CreateSettingsSyncProcessor(it->first).Pass()); CreateSettingsSyncProcessor(extension_id).Pass());
grouped_sync_data.erase(it->first); grouped_sync_data.erase(group);
} else { } else {
base::DictionaryValue empty; error = storage->StartSyncing(
error = it->second->StartSyncing( EmptyDictionaryValue(),
empty, CreateSettingsSyncProcessor(it->first).Pass()); CreateSettingsSyncProcessor(extension_id).Pass());
} }
if (error.IsSet()) if (error.IsSet())
it->second->StopSyncing(); storage->StopSyncing();
} }
// Eagerly create and init the rest of the storage areas that have sync data. // Eagerly create and init the rest of the storage areas that have sync data.
// Under normal circumstances (i.e. not first-time sync) this will be all of // Under normal circumstances (i.e. not first-time sync) this will be all of
// them. // them.
for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it = for (const auto& group : grouped_sync_data) {
grouped_sync_data.begin(); GetOrCreateStorageWithSyncData(group.first, make_scoped_ptr(group.second));
it != grouped_sync_data.end();
++it) {
GetOrCreateStorageWithSyncData(it->first, *it->second);
} }
return syncer::SyncMergeResult(type); return syncer::SyncMergeResult(type);
...@@ -235,23 +232,24 @@ syncer::SyncError SyncStorageBackend::ProcessSyncChanges( ...@@ -235,23 +232,24 @@ syncer::SyncError SyncStorageBackend::ProcessSyncChanges(
DCHECK(sync_processor_.get()); DCHECK(sync_processor_.get());
// Group changes by extension, to pass all changes in a single method call. // Group changes by extension, to pass all changes in a single method call.
std::map<std::string, SettingSyncDataList> grouped_sync_data; // The raw pointers are safe because ownership of each item is passed to
for (syncer::SyncChangeList::const_iterator it = sync_changes.begin(); // storage->ProcessSyncChanges.
it != sync_changes.end(); std::map<std::string, SettingSyncDataList*> grouped_sync_data;
++it) {
SettingSyncData data(*it); for (const syncer::SyncChange& change : sync_changes) {
grouped_sync_data[data.extension_id()].push_back(data); scoped_ptr<SettingSyncData> data(new SettingSyncData(change));
SettingSyncDataList*& group = grouped_sync_data[data->extension_id()];
if (!group)
group = new SettingSyncDataList();
group->push_back(data.Pass());
} }
// Create any storage areas that don't exist yet but have sync data. // Create any storage areas that don't exist yet but have sync data.
base::DictionaryValue empty; for (const auto& group : grouped_sync_data) {
for (std::map<std::string, SettingSyncDataList>::iterator it =
grouped_sync_data.begin();
it != grouped_sync_data.end();
++it) {
SyncableSettingsStorage* storage = SyncableSettingsStorage* storage =
GetOrCreateStorageWithSyncData(it->first, empty); GetOrCreateStorageWithSyncData(group.first, EmptyDictionaryValue());
syncer::SyncError error = storage->ProcessSyncChanges(it->second); syncer::SyncError error =
storage->ProcessSyncChanges(make_scoped_ptr(group.second));
if (error.IsSet()) if (error.IsSet())
storage->StopSyncing(); storage->StopSyncing();
} }
...@@ -264,12 +262,10 @@ void SyncStorageBackend::StopSyncing(syncer::ModelType type) { ...@@ -264,12 +262,10 @@ void SyncStorageBackend::StopSyncing(syncer::ModelType type) {
DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS); DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
DCHECK_EQ(sync_type_, type); DCHECK_EQ(sync_type_, type);
for (StorageObjMap::iterator it = storage_objs_.begin(); for (const auto& storage_obj : storage_objs_) {
it != storage_objs_.end();
++it) {
// Some storage areas may have already stopped syncing if they had areas // Some storage areas may have already stopped syncing if they had areas
// and syncing was disabled, but StopSyncing is safe to call multiple times. // and syncing was disabled, but StopSyncing is safe to call multiple times.
it->second->StopSyncing(); storage_obj.second->StopSyncing();
} }
sync_processor_.reset(); sync_processor_.reset();
......
...@@ -67,7 +67,7 @@ class SyncStorageBackend : public syncer::SyncableService { ...@@ -67,7 +67,7 @@ class SyncStorageBackend : public syncer::SyncableService {
// initializing sync with some initial data if sync enabled. // initializing sync with some initial data if sync enabled.
SyncableSettingsStorage* GetOrCreateStorageWithSyncData( SyncableSettingsStorage* GetOrCreateStorageWithSyncData(
const std::string& extension_id, const std::string& extension_id,
const base::DictionaryValue& sync_data) const; scoped_ptr<base::DictionaryValue> sync_data) const;
// Gets all extension IDs known to extension settings. This may not be all // Gets all extension IDs known to extension settings. This may not be all
// installed extensions. // installed extensions.
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
#include "sync/api/sync_data.h" #include "sync/api/sync_data.h"
#include "sync/protocol/extension_setting_specifics.pb.h" #include "sync/protocol/extension_setting_specifics.pb.h"
namespace extensions {
using content::BrowserThread; using content::BrowserThread;
namespace extensions {
SyncableSettingsStorage::SyncableSettingsStorage( SyncableSettingsStorage::SyncableSettingsStorage(
const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >& const scoped_refptr<ObserverListThreadSafe<SettingsObserver> >&
observers, observers,
...@@ -164,102 +164,97 @@ void SyncableSettingsStorage::SyncResultIfEnabled( ...@@ -164,102 +164,97 @@ void SyncableSettingsStorage::SyncResultIfEnabled(
// Sync-related methods. // Sync-related methods.
syncer::SyncError SyncableSettingsStorage::StartSyncing( syncer::SyncError SyncableSettingsStorage::StartSyncing(
const base::DictionaryValue& sync_state, scoped_ptr<base::DictionaryValue> sync_state,
scoped_ptr<SettingsSyncProcessor> sync_processor) { scoped_ptr<SettingsSyncProcessor> sync_processor) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(sync_state);
DCHECK(!sync_processor_.get()); DCHECK(!sync_processor_.get());
sync_processor_ = sync_processor.Pass(); sync_processor_ = sync_processor.Pass();
sync_processor_->Init(sync_state); sync_processor_->Init(*sync_state);
ReadResult maybe_settings = delegate_->Get(); ReadResult maybe_settings = delegate_->Get();
if (maybe_settings->HasError()) { if (maybe_settings->HasError()) {
return syncer::SyncError( return syncer::SyncError(
FROM_HERE, FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
syncer::SyncError::DATATYPE_ERROR,
base::StringPrintf("Failed to get settings: %s", base::StringPrintf("Failed to get settings: %s",
maybe_settings->error().message.c_str()), maybe_settings->error().message.c_str()),
sync_processor_->type()); sync_processor_->type());
} }
const base::DictionaryValue& settings = maybe_settings->settings(); scoped_ptr<base::DictionaryValue> current_settings =
return sync_state.empty() ? maybe_settings->PassSettings();
SendLocalSettingsToSync(settings) : return sync_state->empty() ? SendLocalSettingsToSync(current_settings.Pass())
OverwriteLocalSettingsWithSync(sync_state, settings); : OverwriteLocalSettingsWithSync(
sync_state.Pass(), current_settings.Pass());
} }
syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync( syncer::SyncError SyncableSettingsStorage::SendLocalSettingsToSync(
const base::DictionaryValue& settings) { scoped_ptr<base::DictionaryValue> local_state) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (local_state->empty())
return syncer::SyncError();
// Transform the current settings into a list of sync changes.
ValueStoreChangeList changes; ValueStoreChangeList changes;
for (base::DictionaryValue::Iterator i(settings); !i.IsAtEnd(); i.Advance()) { while (!local_state->empty()) {
changes.push_back(ValueStoreChange(i.key(), NULL, i.value().DeepCopy())); // 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); syncer::SyncError error = sync_processor_->SendChanges(changes);
if (error.IsSet()) if (error.IsSet())
StopSyncing(); StopSyncing();
return error; return error;
} }
syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync( syncer::SyncError SyncableSettingsStorage::OverwriteLocalSettingsWithSync(
const base::DictionaryValue& sync_state, scoped_ptr<base::DictionaryValue> sync_state,
const base::DictionaryValue& settings) { scoped_ptr<base::DictionaryValue> local_state) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK_CURRENTLY_ON(BrowserThread::FILE);
// Treat this as a list of changes to sync and use ProcessSyncChanges. // This is implemented by building up a list of sync changes then sending
// This gives notifications etc for free. // those to ProcessSyncChanges. This generates events like onStorageChanged.
scoped_ptr<base::DictionaryValue> new_sync_state(sync_state.DeepCopy()); scoped_ptr<SettingSyncDataList> changes(new SettingSyncDataList());
SettingSyncDataList changes; for (base::DictionaryValue::Iterator it(*local_state); !it.IsAtEnd();
for (base::DictionaryValue::Iterator it(settings); it.Advance()) {
!it.IsAtEnd(); it.Advance()) {
scoped_ptr<base::Value> sync_value; 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())) { if (sync_value->Equals(&it.value())) {
// Sync and local values are the same, no changes to send. // Sync and local values are the same, no changes to send.
} else { } else {
// Sync value is different, update local setting with new value. // Sync value is different, update local setting with new value.
changes.push_back( changes->push_back(
SettingSyncData( new SettingSyncData(syncer::SyncChange::ACTION_UPDATE,
syncer::SyncChange::ACTION_UPDATE, extension_id_, it.key(), sync_value.Pass()));
extension_id_,
it.key(),
sync_value.Pass()));
} }
} else { } else {
// Not synced, delete local setting. // Not synced, delete local setting.
changes.push_back( changes->push_back(new SettingSyncData(
SettingSyncData( syncer::SyncChange::ACTION_DELETE, extension_id_, it.key(),
syncer::SyncChange::ACTION_DELETE, scoped_ptr<base::Value>(new base::DictionaryValue())));
extension_id_,
it.key(),
scoped_ptr<base::Value>(new base::DictionaryValue())));
} }
} }
// Add all new settings to local settings. // Add all new settings to local settings.
while (!new_sync_state->empty()) { while (!sync_state->empty()) {
base::DictionaryValue::Iterator first_entry(*new_sync_state); // It's not possible to iterate over a DictionaryValue and modify it at the
std::string key = first_entry.key(); // same time, so hack around that restriction.
std::string key = base::DictionaryValue::Iterator(*sync_state).key();
scoped_ptr<base::Value> value; scoped_ptr<base::Value> value;
CHECK(new_sync_state->RemoveWithoutPathExpansion(key, &value)); CHECK(sync_state->RemoveWithoutPathExpansion(key, &value));
changes.push_back( changes->push_back(new SettingSyncData(syncer::SyncChange::ACTION_ADD,
SettingSyncData( extension_id_, key, value.Pass()));
syncer::SyncChange::ACTION_ADD,
extension_id_,
key,
value.Pass()));
} }
if (changes.empty()) if (changes->empty())
return syncer::SyncError(); return syncer::SyncError();
return ProcessSyncChanges(changes.Pass());
return ProcessSyncChanges(changes);
} }
void SyncableSettingsStorage::StopSyncing() { void SyncableSettingsStorage::StopSyncing() {
...@@ -268,9 +263,9 @@ void SyncableSettingsStorage::StopSyncing() { ...@@ -268,9 +263,9 @@ void SyncableSettingsStorage::StopSyncing() {
} }
syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
const SettingSyncDataList& sync_changes) { scoped_ptr<SettingSyncDataList> sync_changes) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE); 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()) { if (!sync_processor_.get()) {
return syncer::SyncError( return syncer::SyncError(
...@@ -283,16 +278,15 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( ...@@ -283,16 +278,15 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
std::vector<syncer::SyncError> errors; std::vector<syncer::SyncError> errors;
ValueStoreChangeList changes; ValueStoreChangeList changes;
for (SettingSyncDataList::const_iterator it = sync_changes.begin(); for (SettingSyncDataList::iterator it = sync_changes->begin();
it != sync_changes.end(); ++it) { it != sync_changes->end(); ++it) {
DCHECK_EQ(extension_id_, it->extension_id()); DCHECK_EQ(extension_id_, (*it)->extension_id());
const std::string& key = (*it)->key();
const std::string& key = it->key(); scoped_ptr<base::Value> change_value = (*it)->PassValue();
const base::Value& value = it->value();
scoped_ptr<base::Value> current_value; scoped_ptr<base::Value> current_value;
{ {
ReadResult maybe_settings = Get(it->key()); ReadResult maybe_settings = Get(key);
if (maybe_settings->HasError()) { if (maybe_settings->HasError()) {
errors.push_back(syncer::SyncError( errors.push_back(syncer::SyncError(
FROM_HERE, FROM_HERE,
...@@ -309,29 +303,29 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( ...@@ -309,29 +303,29 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
syncer::SyncError error; syncer::SyncError error;
switch (it->change_type()) { switch ((*it)->change_type()) {
case syncer::SyncChange::ACTION_ADD: case syncer::SyncChange::ACTION_ADD:
if (!current_value.get()) { if (!current_value.get()) {
error = OnSyncAdd(key, value.DeepCopy(), &changes); error = OnSyncAdd(key, change_value.release(), &changes);
} else { } else {
// Already a value; hopefully a local change has beaten sync in a // 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 " << LOG(WARNING) << "Got add from sync for existing setting " <<
extension_id_ << "/" << key; extension_id_ << "/" << key;
error = OnSyncUpdate( error = OnSyncUpdate(key, current_value.release(),
key, current_value.release(), value.DeepCopy(), &changes); change_value.release(), &changes);
} }
break; break;
case syncer::SyncChange::ACTION_UPDATE: case syncer::SyncChange::ACTION_UPDATE:
if (current_value.get()) { if (current_value.get()) {
error = OnSyncUpdate( error = OnSyncUpdate(key, current_value.release(),
key, current_value.release(), value.DeepCopy(), &changes); change_value.release(), &changes);
} else { } else {
// Similarly, pretend it's an add. // Similarly, pretend change's an add.
LOG(WARNING) << "Got update from sync for nonexistent setting" << LOG(WARNING) << "Got update from sync for nonexistent setting" <<
extension_id_ << "/" << key; extension_id_ << "/" << key;
error = OnSyncAdd(key, value.DeepCopy(), &changes); error = OnSyncAdd(key, change_value.release(), &changes);
} }
break; break;
...@@ -339,7 +333,7 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges( ...@@ -339,7 +333,7 @@ syncer::SyncError SyncableSettingsStorage::ProcessSyncChanges(
if (current_value.get()) { if (current_value.get()) {
error = OnSyncDelete(key, current_value.release(), &changes); error = OnSyncDelete(key, current_value.release(), &changes);
} else { } else {
// Similarly, ignore it. // Similarly, ignore change.
LOG(WARNING) << "Got delete from sync for nonexistent setting " << LOG(WARNING) << "Got delete from sync for nonexistent setting " <<
extension_id_ << "/" << key; extension_id_ << "/" << key;
} }
......
...@@ -55,31 +55,41 @@ class SyncableSettingsStorage : public ValueStore { ...@@ -55,31 +55,41 @@ class SyncableSettingsStorage : public ValueStore {
// ExtensionSettings), but with looser guarantees about when the methods // ExtensionSettings), but with looser guarantees about when the methods
// can be called. // can be called.
// Must only be called if sync isn't already active. // Starts syncing this storage area. Must only be called if sync isn't
// already active.
// |sync_state| is the current state of the extension settings in sync.
// |sync_processor| is used to write out any changes.
// Returns any error when trying to sync, or an empty error on success.
syncer::SyncError StartSyncing( syncer::SyncError StartSyncing(
const base::DictionaryValue& sync_state, scoped_ptr<base::DictionaryValue> sync_state,
scoped_ptr<SettingsSyncProcessor> sync_processor); scoped_ptr<SettingsSyncProcessor> sync_processor);
// May be called at any time (idempotent). // Stops syncing this storage area. May be called at any time (idempotent).
void StopSyncing(); void StopSyncing();
// May be called at any time; changes will be ignored if sync isn't active. // Pushes a list of sync changes into this storage area. May be called at any
syncer::SyncError ProcessSyncChanges(const SettingSyncDataList& sync_changes); // time, changes will be ignored if sync isn't active.
// Returns any error when trying to sync, or an empty error on success.
syncer::SyncError ProcessSyncChanges(
scoped_ptr<SettingSyncDataList> sync_changes);
private: private:
// Sends the changes from |result| to sync if it's enabled. // Sends the changes from |result| to sync if it's enabled.
void SyncResultIfEnabled(const ValueStore::WriteResult& result); void SyncResultIfEnabled(const ValueStore::WriteResult& result);
// Sends all local settings to sync (synced settings assumed to be empty). // Sends all local settings to sync. This assumes that there are no settings
// in sync yet.
// Returns any error when trying to sync, or an empty error on success.
syncer::SyncError SendLocalSettingsToSync( syncer::SyncError SendLocalSettingsToSync(
const base::DictionaryValue& settings); scoped_ptr<base::DictionaryValue> local_state);
// Overwrites local state with sync state. // Overwrites local state with sync state.
// Returns any error when trying to sync, or an empty error on success.
syncer::SyncError OverwriteLocalSettingsWithSync( syncer::SyncError OverwriteLocalSettingsWithSync(
const base::DictionaryValue& sync_state, scoped_ptr<base::DictionaryValue> sync_state,
const base::DictionaryValue& settings); scoped_ptr<base::DictionaryValue> local_state);
// Called when an Add/Update/Remove comes from sync. Ownership of Value*s // Called when an Add/Update/Remove comes from sync. Ownership of Value*s
// are taken. // are taken.
syncer::SyncError OnSyncAdd( syncer::SyncError OnSyncAdd(
const std::string& key, const std::string& key,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment