OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/extension_settings_leveldb_storage.h" | 5 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 const std::string& key) { | 80 const std::string& key) { |
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
82 scoped_ptr<Value> setting; | 82 scoped_ptr<Value> setting; |
83 if (!ReadFromDb(leveldb::ReadOptions(), key, &setting)) { | 83 if (!ReadFromDb(leveldb::ReadOptions(), key, &setting)) { |
84 return Result(kGenericOnFailureMessage); | 84 return Result(kGenericOnFailureMessage); |
85 } | 85 } |
86 DictionaryValue* settings = new DictionaryValue(); | 86 DictionaryValue* settings = new DictionaryValue(); |
87 if (setting.get()) { | 87 if (setting.get()) { |
88 settings->SetWithoutPathExpansion(key, setting.release()); | 88 settings->SetWithoutPathExpansion(key, setting.release()); |
89 } | 89 } |
90 return Result(settings, NULL); | 90 return Result(settings, NULL, NULL); |
91 } | 91 } |
92 | 92 |
93 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Get( | 93 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Get( |
94 const std::vector<std::string>& keys) { | 94 const std::vector<std::string>& keys) { |
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
96 leveldb::ReadOptions options; | 96 leveldb::ReadOptions options; |
97 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); | 97 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); |
98 | 98 |
99 // All interaction with the db is done on the same thread, so snapshotting | 99 // All interaction with the db is done on the same thread, so snapshotting |
100 // isn't strictly necessary. This is just defensive. | 100 // isn't strictly necessary. This is just defensive. |
101 ScopedSnapshot snapshot(db_.get()); | 101 ScopedSnapshot snapshot(db_.get()); |
102 options.snapshot = snapshot.get(); | 102 options.snapshot = snapshot.get(); |
103 for (std::vector<std::string>::const_iterator it = keys.begin(); | 103 for (std::vector<std::string>::const_iterator it = keys.begin(); |
104 it != keys.end(); ++it) { | 104 it != keys.end(); ++it) { |
105 scoped_ptr<Value> setting; | 105 scoped_ptr<Value> setting; |
106 if (!ReadFromDb(options, *it, &setting)) { | 106 if (!ReadFromDb(options, *it, &setting)) { |
107 return Result(kGenericOnFailureMessage); | 107 return Result(kGenericOnFailureMessage); |
108 } | 108 } |
109 if (setting.get()) { | 109 if (setting.get()) { |
110 settings->SetWithoutPathExpansion(*it, setting.release()); | 110 settings->SetWithoutPathExpansion(*it, setting.release()); |
111 } | 111 } |
112 } | 112 } |
113 | 113 |
114 return Result(settings.release(), NULL); | 114 return Result(settings.release(), NULL, NULL); |
115 } | 115 } |
116 | 116 |
117 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Get() { | 117 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Get() { |
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
119 base::JSONReader json_reader; | 119 base::JSONReader json_reader; |
120 leveldb::ReadOptions options = leveldb::ReadOptions(); | 120 leveldb::ReadOptions options = leveldb::ReadOptions(); |
121 // All interaction with the db is done on the same thread, so snapshotting | 121 // All interaction with the db is done on the same thread, so snapshotting |
122 // isn't strictly necessary. This is just defensive. | 122 // isn't strictly necessary. This is just defensive. |
123 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); | 123 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); |
124 | 124 |
125 ScopedSnapshot snapshot(db_.get()); | 125 ScopedSnapshot snapshot(db_.get()); |
126 options.snapshot = snapshot.get(); | 126 options.snapshot = snapshot.get(); |
127 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); | 127 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); |
128 for (it->SeekToFirst(); it->Valid(); it->Next()) { | 128 for (it->SeekToFirst(); it->Valid(); it->Next()) { |
129 Value* value = | 129 Value* value = |
130 json_reader.JsonToValue(it->value().ToString(), false, false); | 130 json_reader.JsonToValue(it->value().ToString(), false, false); |
131 if (value != NULL) { | 131 if (value != NULL) { |
132 settings->SetWithoutPathExpansion(it->key().ToString(), value); | 132 settings->SetWithoutPathExpansion(it->key().ToString(), value); |
133 } else { | 133 } else { |
134 // TODO(kalman): clear the offending non-JSON value from the database. | 134 // TODO(kalman): clear the offending non-JSON value from the database. |
135 LOG(ERROR) << "Invalid JSON: " << it->value().ToString(); | 135 LOG(ERROR) << "Invalid JSON: " << it->value().ToString(); |
136 } | 136 } |
137 } | 137 } |
138 | 138 |
139 if (!it->status().ok()) { | 139 if (!it->status().ok()) { |
140 LOG(ERROR) << "DB iteration failed: " << it->status().ToString(); | 140 LOG(ERROR) << "DB iteration failed: " << it->status().ToString(); |
141 return Result(kGenericOnFailureMessage); | 141 return Result(kGenericOnFailureMessage); |
142 } | 142 } |
143 | 143 |
144 return Result(settings.release(), NULL); | 144 return Result(settings.release(), NULL, NULL); |
145 } | 145 } |
146 | 146 |
147 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Set( | 147 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Set( |
148 const std::string& key, const Value& value) { | 148 const std::string& key, const Value& value) { |
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
150 DictionaryValue settings; | 150 DictionaryValue settings; |
151 settings.SetWithoutPathExpansion(key, value.DeepCopy()); | 151 settings.SetWithoutPathExpansion(key, value.DeepCopy()); |
152 return Set(settings); | 152 return Set(settings); |
153 } | 153 } |
154 | 154 |
155 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Set( | 155 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Set( |
156 const DictionaryValue& settings) { | 156 const DictionaryValue& settings) { |
157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
158 scoped_ptr<DictionaryValue> old_settings(new DictionaryValue()); | |
158 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); | 159 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); |
159 std::string value_as_json; | 160 std::string value_as_json; |
160 leveldb::WriteBatch batch; | 161 leveldb::WriteBatch batch; |
161 | 162 |
162 for (DictionaryValue::key_iterator it = settings.begin_keys(); | 163 for (DictionaryValue::key_iterator it = settings.begin_keys(); |
163 it != settings.end_keys(); ++it) { | 164 it != settings.end_keys(); ++it) { |
164 scoped_ptr<Value> original_value; | 165 scoped_ptr<Value> old_value; |
165 if (!ReadFromDb(leveldb::ReadOptions(), *it, &original_value)) { | 166 if (!ReadFromDb(leveldb::ReadOptions(), *it, &old_value)) { |
166 return Result(kGenericOnFailureMessage); | 167 return Result(kGenericOnFailureMessage); |
167 } | 168 } |
168 | 169 |
169 Value* new_value = NULL; | 170 Value* new_value = NULL; |
170 settings.GetWithoutPathExpansion(*it, &new_value); | 171 settings.GetWithoutPathExpansion(*it, &new_value); |
171 if (!original_value.get() || !original_value->Equals(new_value)) { | 172 if (!old_value.get() || !old_value->Equals(new_value)) { |
172 changed_keys->insert(*it); | 173 changed_keys->insert(*it); |
173 base::JSONWriter::Write(new_value, false, &value_as_json); | 174 base::JSONWriter::Write(new_value, false, &value_as_json); |
174 batch.Put(*it, value_as_json); | 175 batch.Put(*it, value_as_json); |
175 } | 176 } |
177 | |
178 if (old_value.get()) { | |
179 old_settings->SetWithoutPathExpansion(*it, old_value.release()); | |
180 } | |
176 } | 181 } |
177 | 182 |
178 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 183 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
179 if (!status.ok()) { | 184 if (!status.ok()) { |
180 LOG(WARNING) << "DB batch write failed: " << status.ToString(); | 185 LOG(WARNING) << "DB batch write failed: " << status.ToString(); |
181 return Result(kGenericOnFailureMessage); | 186 return Result(kGenericOnFailureMessage); |
182 } | 187 } |
183 | 188 |
184 return Result(settings.DeepCopy(), changed_keys.release()); | 189 return Result( |
190 settings.DeepCopy(), old_settings.release(), changed_keys.release()); | |
185 } | 191 } |
186 | 192 |
187 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Remove( | 193 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Remove( |
188 const std::string& key) { | 194 const std::string& key) { |
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
190 std::vector<std::string> keys; | 196 std::vector<std::string> keys; |
191 keys.push_back(key); | 197 keys.push_back(key); |
192 return Remove(keys); | 198 return Remove(keys); |
193 } | 199 } |
194 | 200 |
195 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Remove( | 201 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Remove( |
196 const std::vector<std::string>& keys) { | 202 const std::vector<std::string>& keys) { |
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
204 scoped_ptr<DictionaryValue> old_settings(new DictionaryValue()); | |
198 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); | 205 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); |
199 | 206 |
200 leveldb::WriteBatch batch; | 207 leveldb::WriteBatch batch; |
201 for (std::vector<std::string>::const_iterator it = keys.begin(); | 208 for (std::vector<std::string>::const_iterator it = keys.begin(); |
202 it != keys.end(); ++it) { | 209 it != keys.end(); ++it) { |
203 scoped_ptr<Value> original_value; | 210 scoped_ptr<Value> old_value; |
204 if (!ReadFromDb(leveldb::ReadOptions(), *it, &original_value)) { | 211 if (!ReadFromDb(leveldb::ReadOptions(), *it, &old_value)) { |
205 return Result(kGenericOnFailureMessage); | 212 return Result(kGenericOnFailureMessage); |
206 } | 213 } |
207 | 214 |
208 if (original_value.get()) { | 215 if (old_value.get()) { |
209 changed_keys->insert(*it); | 216 changed_keys->insert(*it); |
217 old_settings->SetWithoutPathExpansion(*it, old_value.release()); | |
210 batch.Delete(*it); | 218 batch.Delete(*it); |
211 } | 219 } |
212 } | 220 } |
213 | 221 |
214 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 222 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
215 if (!status.ok() && !status.IsNotFound()) { | 223 if (!status.ok() && !status.IsNotFound()) { |
216 LOG(WARNING) << "DB batch delete failed: " << status.ToString(); | 224 LOG(WARNING) << "DB batch delete failed: " << status.ToString(); |
217 return Result(kGenericOnFailureMessage); | 225 return Result(kGenericOnFailureMessage); |
218 } | 226 } |
219 | 227 |
220 return Result(NULL, changed_keys.release()); | 228 return Result(NULL, old_settings.release(), changed_keys.release()); |
221 } | 229 } |
222 | 230 |
223 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Clear() { | 231 ExtensionSettingsStorage::Result ExtensionSettingsLeveldbStorage::Clear() { |
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
233 scoped_ptr<DictionaryValue> old_settings(new DictionaryValue()); | |
225 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); | 234 scoped_ptr<std::set<std::string> > changed_keys(new std::set<std::string>()); |
226 leveldb::ReadOptions options; | 235 leveldb::ReadOptions options; |
227 // All interaction with the db is done on the same thread, so snapshotting | 236 // All interaction with the db is done on the same thread, so snapshotting |
228 // isn't strictly necessary. This is just defensive. | 237 // isn't strictly necessary. This is just defensive. |
229 leveldb::WriteBatch batch; | 238 leveldb::WriteBatch batch; |
230 | 239 |
231 ScopedSnapshot snapshot(db_.get()); | 240 ScopedSnapshot snapshot(db_.get()); |
232 options.snapshot = snapshot.get(); | 241 options.snapshot = snapshot.get(); |
233 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); | 242 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); |
234 for (it->SeekToFirst(); it->Valid(); it->Next()) { | 243 for (it->SeekToFirst(); it->Valid(); it->Next()) { |
235 changed_keys->insert(it->key().ToString()); | 244 const std::string key = it->key().ToString(); |
236 batch.Delete(it->key()); | 245 const std::string old_value_as_json = it->value().ToString(); |
246 changed_keys->insert(key); | |
247 Value* old_value = | |
248 base::JSONReader().JsonToValue(old_value_as_json, false, false); | |
Matt Perry
2011/10/07 22:39:52
I don't understand this conversion to/from json. W
not at google - send to devlin
2011/10/10 01:00:16
I don't understand... what conversion?
Matt Perry
2011/10/10 20:37:15
old_value is the same as it->value()->DeepCopy(),
not at google - send to devlin
2011/10/10 22:57:53
Still puzzled, "it" is a leveldb iterator, it->val
Matt Perry
2011/10/10 23:01:17
Oops, my mistake! Reading comprehension fail... Ig
not at google - send to devlin
2011/10/11 03:58:48
np
| |
249 if (old_value) { | |
250 old_settings->SetWithoutPathExpansion(key, old_value); | |
251 } else { | |
252 // TODO(kalman): clear the offending non-JSON value from the database. | |
253 LOG(ERROR) << "Invalid JSON in database: " << old_value_as_json; | |
254 } | |
255 batch.Delete(key); | |
237 } | 256 } |
238 | 257 |
239 if (!it->status().ok()) { | 258 if (!it->status().ok()) { |
240 LOG(WARNING) << "Clear iteration failed: " << it->status().ToString(); | 259 LOG(WARNING) << "Clear iteration failed: " << it->status().ToString(); |
241 return Result(kGenericOnFailureMessage); | 260 return Result(kGenericOnFailureMessage); |
242 } | 261 } |
243 | 262 |
244 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 263 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
245 if (!status.ok() && !status.IsNotFound()) { | 264 if (!status.ok() && !status.IsNotFound()) { |
246 LOG(WARNING) << "Clear failed: " << status.ToString(); | 265 LOG(WARNING) << "Clear failed: " << status.ToString(); |
247 return Result(kGenericOnFailureMessage); | 266 return Result(kGenericOnFailureMessage); |
248 } | 267 } |
249 | 268 |
250 return Result(NULL, changed_keys.release()); | 269 return Result(NULL, old_settings.release(), changed_keys.release()); |
251 } | 270 } |
252 | 271 |
253 bool ExtensionSettingsLeveldbStorage::ReadFromDb( | 272 bool ExtensionSettingsLeveldbStorage::ReadFromDb( |
254 leveldb::ReadOptions options, | 273 leveldb::ReadOptions options, |
255 const std::string& key, | 274 const std::string& key, |
256 scoped_ptr<Value>* setting) { | 275 scoped_ptr<Value>* setting) { |
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
258 DCHECK(setting != NULL); | 277 DCHECK(setting != NULL); |
259 std::string value_as_json; | 278 std::string value_as_json; |
260 leveldb::Status s = db_->Get(options, key, &value_as_json); | 279 leveldb::Status s = db_->Get(options, key, &value_as_json); |
(...skipping 11 matching lines...) Expand all Loading... | |
272 Value* value = base::JSONReader().JsonToValue(value_as_json, false, false); | 291 Value* value = base::JSONReader().JsonToValue(value_as_json, false, false); |
273 if (value == NULL) { | 292 if (value == NULL) { |
274 // TODO(kalman): clear the offending non-JSON value from the database. | 293 // TODO(kalman): clear the offending non-JSON value from the database. |
275 LOG(ERROR) << "Invalid JSON in database: " << value_as_json; | 294 LOG(ERROR) << "Invalid JSON in database: " << value_as_json; |
276 return false; | 295 return false; |
277 } | 296 } |
278 | 297 |
279 setting->reset(value); | 298 setting->reset(value); |
280 return true; | 299 return true; |
281 } | 300 } |
OLD | NEW |