Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: chrome/browser/extensions/api/storage/sync_storage_backend.cc

Issue 175853002: Revert of Add a Restore() method to ValueStore and make StorageAPI use it (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "chrome/browser/extensions/api/storage/sync_storage_backend.h"
6
7 #include "base/files/file_enumerator.h"
8 #include "base/logging.h"
9 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h"
10 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"
11 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "sync/api/sync_error_factory.h"
14
15 using content::BrowserThread;
16
17 namespace extensions {
18
19 namespace {
20
21 void AddAllSyncData(const std::string& extension_id,
22 const base::DictionaryValue& src,
23 syncer::ModelType type,
24 syncer::SyncDataList* dst) {
25 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
26 dst->push_back(settings_sync_util::CreateData(
27 extension_id, it.key(), it.value(), type));
28 }
29 }
30
31 } // namespace
32
33 SyncStorageBackend::SyncStorageBackend(
34 const scoped_refptr<SettingsStorageFactory>& storage_factory,
35 const base::FilePath& base_path,
36 const SettingsStorageQuotaEnforcer::Limits& quota,
37 const scoped_refptr<SettingsObserverList>& observers,
38 syncer::ModelType sync_type,
39 const syncer::SyncableService::StartSyncFlare& flare)
40 : SettingsBackend(storage_factory, base_path, quota),
41 observers_(observers),
42 sync_type_(sync_type),
43 flare_(flare) {
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
45 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS ||
46 sync_type_ == syncer::APP_SETTINGS);
47 }
48
49 SyncStorageBackend::~SyncStorageBackend() {}
50
51 ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
53 base::DictionaryValue empty;
54 return GetOrCreateStorageWithSyncData(extension_id, empty);
55 }
56
57 SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData(
58 const std::string& extension_id,
59 const base::DictionaryValue& sync_data) const {
60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
61
62 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
63 if (maybe_storage != storage_objs_.end()) {
64 return maybe_storage->second.get();
65 }
66
67 scoped_ptr<SettingsStorageQuotaEnforcer> storage =
68 CreateStorageForExtension(extension_id);
69
70 // It's fine to create the quota enforcer underneath the sync layer, since
71 // sync will only go ahead if each underlying storage operation succeeds.
72 linked_ptr<SyncableSettingsStorage> syncable_storage(
73 new SyncableSettingsStorage(
74 observers_, extension_id, storage.release(), sync_type_, flare_));
75 storage_objs_[extension_id] = syncable_storage;
76
77 if (sync_processor_.get()) {
78 syncer::SyncError error = syncable_storage->StartSyncing(
79 sync_data, CreateSettingsSyncProcessor(extension_id).Pass());
80 if (error.IsSet())
81 syncable_storage.get()->StopSyncing();
82 }
83 return syncable_storage.get();
84 }
85
86 void SyncStorageBackend::DeleteStorage(const std::string& extension_id) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
88
89 // Clear settings when the extension is uninstalled. Leveldb implementations
90 // will also delete the database from disk when the object is destroyed as a
91 // result of being removed from |storage_objs_|.
92 //
93 // TODO(kalman): always GetStorage here (rather than only clearing if it
94 // exists) since the storage area may have been unloaded, but we still want
95 // to clear the data from disk.
96 // However, this triggers http://crbug.com/111072.
97 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
98 if (maybe_storage == storage_objs_.end())
99 return;
100 maybe_storage->second->Clear();
101 storage_objs_.erase(extension_id);
102 }
103
104 syncer::SyncableService* SyncStorageBackend::GetAsSyncableService() {
105 return this;
106 }
107
108 std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const {
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
110 std::set<std::string> result;
111
112 // Storage areas can be in-memory as well as on disk. |storage_objs_| will
113 // contain all that are in-memory.
114 for (StorageObjMap::iterator it = storage_objs_.begin();
115 it != storage_objs_.end();
116 ++it) {
117 result.insert(it->first);
118 }
119
120 // Leveldb databases are directories inside base_path().
121 base::FileEnumerator extension_dirs(
122 base_path(), false, base::FileEnumerator::DIRECTORIES);
123 while (!extension_dirs.Next().empty()) {
124 base::FilePath extension_dir = extension_dirs.GetInfo().GetName();
125 DCHECK(!extension_dir.IsAbsolute());
126 // Extension IDs are created as std::strings so they *should* be ASCII.
127 std::string maybe_as_ascii(extension_dir.MaybeAsASCII());
128 if (!maybe_as_ascii.empty()) {
129 result.insert(maybe_as_ascii);
130 }
131 }
132
133 return result;
134 }
135
136 syncer::SyncDataList SyncStorageBackend::GetAllSyncData(syncer::ModelType type)
137 const {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
139 // Ignore the type, it's just for sanity checking; assume that whatever base
140 // path we're constructed with is correct for the sync type.
141 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
142
143 // For all extensions, get all their settings. This has the effect
144 // of bringing in the entire state of extension settings in memory; sad.
145 syncer::SyncDataList all_sync_data;
146 std::set<std::string> known_extension_ids(GetKnownExtensionIDs());
147
148 for (std::set<std::string>::const_iterator it = known_extension_ids.begin();
149 it != known_extension_ids.end();
150 ++it) {
151 ValueStore::ReadResult maybe_settings =
152 GetOrCreateStorageWithSyncData(*it, base::DictionaryValue())->Get();
153 if (maybe_settings->HasError()) {
154 LOG(WARNING) << "Failed to get settings for " << *it << ": "
155 << maybe_settings->error().message;
156 continue;
157 }
158 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data);
159 }
160
161 return all_sync_data;
162 }
163
164 syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing(
165 syncer::ModelType type,
166 const syncer::SyncDataList& initial_sync_data,
167 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
168 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170 DCHECK_EQ(sync_type_, type);
171 DCHECK(!sync_processor_.get());
172 DCHECK(sync_processor.get());
173 DCHECK(sync_error_factory.get());
174
175 sync_processor_ = sync_processor.Pass();
176 sync_error_factory_ = sync_error_factory.Pass();
177
178 // Group the initial sync data by extension id.
179 std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data;
180 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
181 it != initial_sync_data.end();
182 ++it) {
183 SettingSyncData data(*it);
184 linked_ptr<base::DictionaryValue> sync_data =
185 grouped_sync_data[data.extension_id()];
186 if (!sync_data.get()) {
187 sync_data =
188 linked_ptr<base::DictionaryValue>(new base::DictionaryValue());
189 grouped_sync_data[data.extension_id()] = sync_data;
190 }
191 DCHECK(!sync_data->HasKey(data.key())) << "Duplicate settings for "
192 << data.extension_id() << "/"
193 << data.key();
194 sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy());
195 }
196
197 // Start syncing all existing storage areas. Any storage areas created in
198 // the future will start being synced as part of the creation process.
199 for (StorageObjMap::iterator it = storage_objs_.begin();
200 it != storage_objs_.end();
201 ++it) {
202 std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator
203 maybe_sync_data = grouped_sync_data.find(it->first);
204 syncer::SyncError error;
205 if (maybe_sync_data != grouped_sync_data.end()) {
206 error = it->second->StartSyncing(
207 *maybe_sync_data->second,
208 CreateSettingsSyncProcessor(it->first).Pass());
209 grouped_sync_data.erase(it->first);
210 } else {
211 base::DictionaryValue empty;
212 error = it->second->StartSyncing(
213 empty, CreateSettingsSyncProcessor(it->first).Pass());
214 }
215 if (error.IsSet())
216 it->second->StopSyncing();
217 }
218
219 // Eagerly create and init the rest of the storage areas that have sync data.
220 // Under normal circumstances (i.e. not first-time sync) this will be all of
221 // them.
222 for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it =
223 grouped_sync_data.begin();
224 it != grouped_sync_data.end();
225 ++it) {
226 GetOrCreateStorageWithSyncData(it->first, *it->second);
227 }
228
229 return syncer::SyncMergeResult(type);
230 }
231
232 syncer::SyncError SyncStorageBackend::ProcessSyncChanges(
233 const tracked_objects::Location& from_here,
234 const syncer::SyncChangeList& sync_changes) {
235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
236 DCHECK(sync_processor_.get());
237
238 // Group changes by extension, to pass all changes in a single method call.
239 std::map<std::string, SettingSyncDataList> grouped_sync_data;
240 for (syncer::SyncChangeList::const_iterator it = sync_changes.begin();
241 it != sync_changes.end();
242 ++it) {
243 SettingSyncData data(*it);
244 grouped_sync_data[data.extension_id()].push_back(data);
245 }
246
247 // Create any storage areas that don't exist yet but have sync data.
248 base::DictionaryValue empty;
249 for (std::map<std::string, SettingSyncDataList>::iterator it =
250 grouped_sync_data.begin();
251 it != grouped_sync_data.end();
252 ++it) {
253 SyncableSettingsStorage* storage =
254 GetOrCreateStorageWithSyncData(it->first, empty);
255 syncer::SyncError error = storage->ProcessSyncChanges(it->second);
256 if (error.IsSet())
257 storage->StopSyncing();
258 }
259
260 return syncer::SyncError();
261 }
262
263 void SyncStorageBackend::StopSyncing(syncer::ModelType type) {
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
265 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
266 DCHECK_EQ(sync_type_, type);
267
268 for (StorageObjMap::iterator it = storage_objs_.begin();
269 it != storage_objs_.end();
270 ++it) {
271 // Some storage areas may have already stopped syncing if they had areas
272 // and syncing was disabled, but StopSyncing is safe to call multiple times.
273 it->second->StopSyncing();
274 }
275
276 sync_processor_.reset();
277 sync_error_factory_.reset();
278 }
279
280 scoped_ptr<SettingsSyncProcessor>
281 SyncStorageBackend::CreateSettingsSyncProcessor(const std::string& extension_id)
282 const {
283 CHECK(sync_processor_.get());
284 return scoped_ptr<SettingsSyncProcessor>(new SettingsSyncProcessor(
285 extension_id, sync_type_, sync_processor_.get()));
286 }
287
288 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698