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

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

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

Powered by Google App Engine
This is Rietveld 408576698