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

Side by Side Diff: components/filesystem/public/cpp/prefs/filesystem_json_pref_store.cc

Issue 1624683002: mash: Add a simple, temporary preferences store. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sky comments Created 4 years, 11 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 "components/filesystem/public/cpp/prefs/filesystem_json_pref_store.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/json/json_string_value_serializer.h"
17 #include "base/logging.h"
18 #include "base/macros.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/prefs/pref_filter.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/task_runner_util.h"
24 #include "base/time/default_clock.h"
25 #include "base/values.h"
26 #include "mojo/common/common_type_converters.h"
27
28 namespace filesystem {
29
30 // Result returned from internal read tasks.
31 struct FilesystemJsonPrefStore::ReadResult {
32 public:
33 ReadResult();
34 ~ReadResult();
35
36 scoped_ptr<base::Value> value;
37 PrefReadError error;
38
39 private:
40 DISALLOW_COPY_AND_ASSIGN(ReadResult);
41 };
42
43 FilesystemJsonPrefStore::ReadResult::ReadResult()
44 : error(PersistentPrefStore::PREF_READ_ERROR_NONE) {}
45
46 FilesystemJsonPrefStore::ReadResult::~ReadResult() {}
47
48 namespace {
49
50 PersistentPrefStore::PrefReadError HandleReadErrors(const base::Value* value) {
51 if (!value->IsType(base::Value::TYPE_DICTIONARY))
52 return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
53 return PersistentPrefStore::PREF_READ_ERROR_NONE;
54 }
55
56 } // namespace
57
58 FilesystemJsonPrefStore::FilesystemJsonPrefStore(
59 const std::string& pref_filename,
60 filesystem::FileSystemPtr filesystem,
61 scoped_ptr<PrefFilter> pref_filter)
62 : path_(pref_filename),
63 binding_(this),
64 filesystem_(std::move(filesystem)),
65 prefs_(new base::DictionaryValue()),
66 read_only_(false),
67 pref_filter_(std::move(pref_filter)),
68 initialized_(false),
69 filtering_in_progress_(false),
70 pending_lossy_write_(false),
71 read_error_(PREF_READ_ERROR_NONE) {
72 DCHECK(!path_.empty());
73 }
74
75 bool FilesystemJsonPrefStore::GetValue(const std::string& key,
76 const base::Value** result) const {
77 DCHECK(CalledOnValidThread());
78
79 base::Value* tmp = nullptr;
80 if (!prefs_->Get(key, &tmp))
81 return false;
82
83 if (result)
84 *result = tmp;
85 return true;
86 }
87
88 void FilesystemJsonPrefStore::AddObserver(PrefStore::Observer* observer) {
89 DCHECK(CalledOnValidThread());
90
91 observers_.AddObserver(observer);
92 }
93
94 void FilesystemJsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
95 DCHECK(CalledOnValidThread());
96
97 observers_.RemoveObserver(observer);
98 }
99
100 bool FilesystemJsonPrefStore::HasObservers() const {
101 DCHECK(CalledOnValidThread());
102
103 return observers_.might_have_observers();
104 }
105
106 bool FilesystemJsonPrefStore::IsInitializationComplete() const {
107 DCHECK(CalledOnValidThread());
108
109 return initialized_;
110 }
111
112 bool FilesystemJsonPrefStore::GetMutableValue(const std::string& key,
113 base::Value** result) {
114 DCHECK(CalledOnValidThread());
115
116 return prefs_->Get(key, result);
117 }
118
119 void FilesystemJsonPrefStore::SetValue(const std::string& key,
120 scoped_ptr<base::Value> value,
121 uint32_t flags) {
122 DCHECK(CalledOnValidThread());
123
124 DCHECK(value);
125 base::Value* old_value = nullptr;
126 prefs_->Get(key, &old_value);
127 if (!old_value || !value->Equals(old_value)) {
128 prefs_->Set(key, std::move(value));
129 ReportValueChanged(key, flags);
130 }
131 }
132
133 void FilesystemJsonPrefStore::SetValueSilently(const std::string& key,
134 scoped_ptr<base::Value> value,
135 uint32_t flags) {
136 DCHECK(CalledOnValidThread());
137
138 DCHECK(value);
139 base::Value* old_value = nullptr;
140 prefs_->Get(key, &old_value);
141 if (!old_value || !value->Equals(old_value)) {
142 prefs_->Set(key, std::move(value));
143 ScheduleWrite(flags);
144 }
145 }
146
147 void FilesystemJsonPrefStore::RemoveValue(const std::string& key,
148 uint32_t flags) {
149 DCHECK(CalledOnValidThread());
150
151 if (prefs_->RemovePath(key, nullptr))
152 ReportValueChanged(key, flags);
153 }
154
155 void FilesystemJsonPrefStore::RemoveValueSilently(const std::string& key,
156 uint32_t flags) {
157 DCHECK(CalledOnValidThread());
158
159 prefs_->RemovePath(key, nullptr);
160 ScheduleWrite(flags);
161 }
162
163 bool FilesystemJsonPrefStore::ReadOnly() const {
164 DCHECK(CalledOnValidThread());
165
166 return read_only_;
167 }
168
169 PersistentPrefStore::PrefReadError FilesystemJsonPrefStore::GetReadError()
170 const {
171 DCHECK(CalledOnValidThread());
172
173 return read_error_;
174 }
175
176 PersistentPrefStore::PrefReadError FilesystemJsonPrefStore::ReadPrefs() {
177 NOTREACHED();
178 // TODO(erg): Synchronously reading files makes no sense in a mojo world and
179 // should be removed from the API.
180 return PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE;
181 }
182
183 void FilesystemJsonPrefStore::ReadPrefsAsync(
184 ReadErrorDelegate* error_delegate) {
185 DCHECK(CalledOnValidThread());
186
187 initialized_ = false;
188 error_delegate_.reset(error_delegate);
189
190 if (!directory_) {
191 OpenFilesystem(
192 Bind(&FilesystemJsonPrefStore::OnPreferencesReadStart, AsWeakPtr()));
193 } else {
194 OnPreferencesReadStart();
195 }
196 }
197
198 void FilesystemJsonPrefStore::CommitPendingWrite() {
199 DCHECK(CalledOnValidThread());
200
201 // TODO(erg): This is another one of those cases where we have problems
202 // because of mismatch between the models used in the pref service versus
203 // here. Most of the time, CommitPendingWrite() is called from
204 // PrefService. However, in JSONPrefStore, we also call this method on
205 // shutdown and thus need to synchronously write. But in mojo:filesystem,
206 // everything is done asynchronously. So we're sort of stuck until we can
207 // change the interface, which we'll do in the longer term.
208
209 SchedulePendingLossyWrites();
210 }
211
212 void FilesystemJsonPrefStore::SchedulePendingLossyWrites() {
213 // This method is misnamed for the sake of the interface. Given that writing
214 // is already asynchronous in this new world, "sheduleing" a pending write
215 // just starts the asynchronous process.
216 if (pending_lossy_write_)
217 PerformWrite();
218 }
219
220 void FilesystemJsonPrefStore::ReportValueChanged(const std::string& key,
221 uint32_t flags) {
222 DCHECK(CalledOnValidThread());
223
224 if (pref_filter_)
225 pref_filter_->FilterUpdate(key);
226
227 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
228
229 ScheduleWrite(flags);
230 }
231
232 void FilesystemJsonPrefStore::OnFileSystemShutdown() {}
233
234 void FilesystemJsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
235 DCHECK(CalledOnValidThread());
236
237 DCHECK(read_result);
238
239 scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
240
241 read_error_ = read_result->error;
242
243 switch (read_error_) {
244 case PREF_READ_ERROR_ACCESS_DENIED:
245 case PREF_READ_ERROR_FILE_OTHER:
246 case PREF_READ_ERROR_FILE_LOCKED:
247 case PREF_READ_ERROR_JSON_TYPE:
248 case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
249 read_only_ = true;
250 break;
251 case PREF_READ_ERROR_NONE:
252 DCHECK(read_result->value.get());
253 unfiltered_prefs.reset(
254 static_cast<base::DictionaryValue*>(read_result->value.release()));
255 break;
256 case PREF_READ_ERROR_NO_FILE:
257 // If the file just doesn't exist, maybe this is first run. In any case
258 // there's no harm in writing out default prefs in this case.
259 case PREF_READ_ERROR_JSON_PARSE:
260 case PREF_READ_ERROR_JSON_REPEAT:
261 break;
262 case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
263 // This is a special error code to be returned by ReadPrefs when it
264 // can't complete synchronously, it should never be returned by the read
265 // operation itself.
266 case PREF_READ_ERROR_MAX_ENUM:
267 NOTREACHED();
268 break;
269 }
270
271 if (pref_filter_) {
272 filtering_in_progress_ = true;
273 const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
274 base::Bind(&FilesystemJsonPrefStore::FinalizeFileRead, AsWeakPtr()));
275 pref_filter_->FilterOnLoad(post_filter_on_load_callback,
276 std::move(unfiltered_prefs));
277 } else {
278 FinalizeFileRead(std::move(unfiltered_prefs), false);
279 }
280 }
281
282 FilesystemJsonPrefStore::~FilesystemJsonPrefStore() {
283 // TODO(erg): Now that writing is asynchronous, we can't really async write
284 // prefs at shutdown. See comment in CommitPendingWrite().
285 }
286
287 void FilesystemJsonPrefStore::FinalizeFileRead(
288 scoped_ptr<base::DictionaryValue> prefs,
289 bool schedule_write) {
290 DCHECK(CalledOnValidThread());
291
292 filtering_in_progress_ = false;
293
294 prefs_ = std::move(prefs);
295
296 initialized_ = true;
297
298 if (schedule_write)
299 ScheduleWrite(DEFAULT_PREF_WRITE_FLAGS);
300
301 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
302 error_delegate_->OnError(read_error_);
303
304 FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
305 OnInitializationCompleted(true));
306
307 return;
308 }
309
310 void FilesystemJsonPrefStore::ScheduleWrite(uint32_t flags) {
311 if (read_only_)
312 return;
313
314 if (flags & LOSSY_PREF_WRITE_FLAG)
315 pending_lossy_write_ = true;
316 else
317 PerformWrite();
318 }
319
320 void FilesystemJsonPrefStore::PerformWrite() {
321 if (!directory_) {
322 OpenFilesystem(
323 Bind(&FilesystemJsonPrefStore::OnTempFileWriteStart, AsWeakPtr()));
324 } else {
325 OnTempFileWriteStart();
326 }
327 }
328
329 void FilesystemJsonPrefStore::OpenFilesystem(base::Closure callback) {
330 filesystem::FileSystemClientPtr client;
331 binding_.Bind(GetProxy(&client));
332
333 filesystem_->OpenFileSystem(
334 "origin", GetProxy(&directory_), std::move(client),
335 base::Bind(&FilesystemJsonPrefStore::OnOpenFilesystem, AsWeakPtr(),
336 callback));
337 }
338
339 void FilesystemJsonPrefStore::OnOpenFilesystem(base::Closure callback,
340 FileError err) {
341 if (err != FileError::OK) {
342 // Do real error checking.
343 NOTIMPLEMENTED();
344 return;
345 }
346
347 callback.Run();
348 }
349
350 void FilesystemJsonPrefStore::OnTempFileWriteStart() {
351 // Open up a temporary file and truncate it.
352 directory_->OpenFile(
353 "tmp", GetProxy(&temporary_file_), kFlagWrite | kFlagCreate,
354 Bind(&FilesystemJsonPrefStore::OnTempFileOpened, AsWeakPtr()));
355 }
356
357 void FilesystemJsonPrefStore::OnTempFileOpened(FileError err) {
358 // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
359 // file can never fail.
360 CHECK_EQ(FileError::OK, err);
361
362 // Calculate what we want to write, and then write to the temporary file.
363 pending_lossy_write_ = false;
364
365 if (pref_filter_)
366 pref_filter_->FilterSerializeData(prefs_.get());
367
368 std::string output;
369 JSONStringValueSerializer serializer(&output);
370 serializer.set_pretty_print(false);
371 serializer.Serialize(*prefs_);
372
373 temporary_file_->Write(
374 mojo::Array<uint8_t>::From(output), 0, Whence::FROM_CURRENT,
375 Bind(&FilesystemJsonPrefStore::OnTempFileWrite, AsWeakPtr()));
376 }
377
378 void FilesystemJsonPrefStore::OnTempFileWrite(FileError err,
379 uint32_t num_bytes_written) {
380 // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
381 // file can never fail.
382 CHECK_EQ(FileError::OK, err);
383
384 // Now that we've written the file, close it.
385 temporary_file_->Close(
386 Bind(&FilesystemJsonPrefStore::OnTempFileClosed, AsWeakPtr()));
387 }
388
389 void FilesystemJsonPrefStore::OnTempFileClosed(FileError err) {
390 // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
391 // file can never fail.
392 CHECK_EQ(FileError::OK, err);
393
394 temporary_file_.reset();
395 directory_->Rename(
396 "tmp", path_,
397 Bind(&FilesystemJsonPrefStore::OnTempFileRenamed, AsWeakPtr()));
398 }
399
400 void FilesystemJsonPrefStore::OnTempFileRenamed(FileError err) {}
401
402 void FilesystemJsonPrefStore::OnPreferencesReadStart() {
403 // TODO(erg): implement me.
404 directory_->OpenFile(
405 path_, GetProxy(&preferences_file_), kFlagRead | kFlagOpen,
406 Bind(&FilesystemJsonPrefStore::OnPreferencesFileOpened, AsWeakPtr()));
407 }
408
409 void FilesystemJsonPrefStore::OnPreferencesFileOpened(FileError err) {
410 // TODO(erg): Error handling.
411 if (err == FileError::OK) {
412 preferences_file_->ReadEntireFile(
413 Bind(&FilesystemJsonPrefStore::OnPreferencesFileRead, AsWeakPtr()));
414 } else {
415 OnPreferencesFileRead(err, mojo::Array<uint8_t>());
416 }
417 }
418
419 void FilesystemJsonPrefStore::OnPreferencesFileRead(
420 FileError err,
421 mojo::Array<uint8_t> contents) {
422 scoped_ptr<FilesystemJsonPrefStore::ReadResult> read_result(
423 new FilesystemJsonPrefStore::ReadResult);
424 // TODO(erg): Needs even better error handling.
425 switch (err) {
426 case FileError::IN_USE:
427 case FileError::ACCESS_DENIED: {
428 read_only_ = true;
429 break;
430 }
431 case FileError::NOT_FOUND: {
432 // If the file just doesn't exist, maybe this is the first run. Just
433 // don't pass a value.
434 read_result->error = PREF_READ_ERROR_NO_FILE;
435 break;
436 }
437 default: {
438 int error_code;
439 std::string error_msg;
440 JSONStringValueDeserializer deserializer(base::StringPiece(
441 reinterpret_cast<char*>(&contents.front()), contents.size()));
442 read_result->value = deserializer.Deserialize(&error_code, &error_msg);
443 read_result->error = HandleReadErrors(read_result->value.get());
444 }
445 }
446
447 preferences_file_.reset();
448
449 OnFileRead(std::move(read_result));
450 }
451
452 } // namespace filesystem
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698