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

Side by Side Diff: chrome/common/pref_service.cc

Issue 83001: ImportantFileWriter (Closed)
Patch Set: share more code Created 11 years, 8 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
« no previous file with comments | « chrome/common/pref_service.h ('k') | chrome/common/pref_service_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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/common/pref_service.h" 5 #include "chrome/common/pref_service.h"
6 6
7 #include "base/compiler_specific.h"
8 #include "base/file_util.h"
9 #include "base/logging.h" 7 #include "base/logging.h"
10 #include "base/message_loop.h" 8 #include "base/message_loop.h"
11 #include "base/string_util.h" 9 #include "base/string_util.h"
12 #include "base/task.h"
13 #include "base/thread.h" 10 #include "base/thread.h"
14 #include "chrome/common/json_value_serializer.h" 11 #include "chrome/common/json_value_serializer.h"
15 #include "chrome/common/l10n_util.h" 12 #include "chrome/common/l10n_util.h"
16 #include "chrome/common/notification_service.h" 13 #include "chrome/common/notification_service.h"
17 #include "chrome/common/stl_util-inl.h" 14 #include "chrome/common/stl_util-inl.h"
18 #include "grit/generated_resources.h" 15 #include "grit/generated_resources.h"
19 16
20 namespace { 17 namespace {
21 18
22 // The number of milliseconds we'll wait to do a write of chrome prefs to disk.
23 // This lets us batch together write operations.
24 static const int kCommitIntervalMs = 10000;
25
26 // Replaces the given file's content with the given data. This allows the
27 // preferences to be written to disk on a background thread.
28 class SaveLaterTask : public Task {
29 public:
30 SaveLaterTask(const FilePath& file_name,
31 const std::string& data)
32 : file_name_(file_name),
33 data_(data) {
34 }
35
36 void Run() {
37 // Write the data to a temp file then rename to avoid data loss if we crash
38 // while writing the file.
39 FilePath tmp_file_name(file_name_.value() + FILE_PATH_LITERAL(".tmp"));
40 int bytes_written = file_util::WriteFile(tmp_file_name, data_.c_str(),
41 static_cast<int>(data_.length()));
42 if (bytes_written != -1) {
43 if (!file_util::Move(tmp_file_name, file_name_)) {
44 // Rename failed. Try again on the off chance someone has locked either
45 // file and hope we're successful the second time through.
46 bool move_result = file_util::Move(tmp_file_name, file_name_);
47 DCHECK(move_result);
48 }
49 }
50 }
51
52 private:
53 FilePath file_name_;
54 std::string data_;
55
56 DISALLOW_COPY_AND_ASSIGN(SaveLaterTask);
57 };
58
59 // A helper function for RegisterLocalized*Pref that creates a Value* based on 19 // A helper function for RegisterLocalized*Pref that creates a Value* based on
60 // the string value in the locale dll. Because we control the values in a 20 // the string value in the locale dll. Because we control the values in a
61 // locale dll, this should always return a Value of the appropriate type. 21 // locale dll, this should always return a Value of the appropriate type.
62 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) { 22 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
63 std::wstring resource_string = l10n_util::GetString(message_id); 23 std::wstring resource_string = l10n_util::GetString(message_id);
64 DCHECK(!resource_string.empty()); 24 DCHECK(!resource_string.empty());
65 switch (type) { 25 switch (type) {
66 case Value::TYPE_BOOLEAN: { 26 case Value::TYPE_BOOLEAN: {
67 if (L"true" == resource_string) 27 if (L"true" == resource_string)
68 return Value::CreateBooleanValue(true); 28 return Value::CreateBooleanValue(true);
(...skipping 23 matching lines...) Expand all
92 NOTREACHED() << 52 NOTREACHED() <<
93 "list and dictionary types can not have default locale values"; 53 "list and dictionary types can not have default locale values";
94 } 54 }
95 } 55 }
96 NOTREACHED(); 56 NOTREACHED();
97 return Value::CreateNullValue(); 57 return Value::CreateNullValue();
98 } 58 }
99 59
100 } // namespace 60 } // namespace
101 61
102 PrefService::PrefService() 62 PrefService::PrefService(const FilePath& pref_filename,
63 const base::Thread* backend_thread)
103 : persistent_(new DictionaryValue), 64 : persistent_(new DictionaryValue),
104 transient_(new DictionaryValue), 65 transient_(new DictionaryValue),
105 save_preferences_factory_(NULL) { 66 writer_(pref_filename, backend_thread) {
106 } 67 ReloadPersistentPrefs();
107
108 PrefService::PrefService(const FilePath& pref_filename)
109 : persistent_(new DictionaryValue),
110 transient_(new DictionaryValue),
111 pref_filename_(pref_filename),
112 ALLOW_THIS_IN_INITIALIZER_LIST(save_preferences_factory_(this)) {
113 LoadPersistentPrefs(pref_filename_);
114 } 68 }
115 69
116 PrefService::~PrefService() { 70 PrefService::~PrefService() {
117 DCHECK(CalledOnValidThread()); 71 DCHECK(CalledOnValidThread());
118 72
119 // Verify that there are no pref observers when we shut down. 73 // Verify that there are no pref observers when we shut down.
120 for (PrefObserverMap::iterator it = pref_observers_.begin(); 74 for (PrefObserverMap::iterator it = pref_observers_.begin();
121 it != pref_observers_.end(); ++it) { 75 it != pref_observers_.end(); ++it) {
122 NotificationObserverList::Iterator obs_iterator(*(it->second)); 76 NotificationObserverList::Iterator obs_iterator(*(it->second));
123 if (obs_iterator.GetNext()) { 77 if (obs_iterator.GetNext()) {
124 LOG(WARNING) << "pref observer found at shutdown " << it->first; 78 LOG(WARNING) << "pref observer found at shutdown " << it->first;
125 } 79 }
126 } 80 }
127 81
128 STLDeleteContainerPointers(prefs_.begin(), prefs_.end()); 82 STLDeleteContainerPointers(prefs_.begin(), prefs_.end());
129 prefs_.clear(); 83 prefs_.clear();
130 STLDeleteContainerPairSecondPointers(pref_observers_.begin(), 84 STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
131 pref_observers_.end()); 85 pref_observers_.end());
132 pref_observers_.clear(); 86 pref_observers_.clear();
133 } 87 }
134 88
135 bool PrefService::LoadPersistentPrefs(const FilePath& file_path) { 89 bool PrefService::ReloadPersistentPrefs() {
136 DCHECK(!file_path.empty());
137 DCHECK(CalledOnValidThread()); 90 DCHECK(CalledOnValidThread());
138 91
139 JSONFileValueSerializer serializer(file_path); 92 JSONFileValueSerializer serializer(writer_.path());
140 scoped_ptr<Value> root(serializer.Deserialize(NULL)); 93 scoped_ptr<Value> root(serializer.Deserialize(NULL));
141 if (!root.get()) 94 if (!root.get())
142 return false; 95 return false;
143 96
144 // Preferences should always have a dictionary root. 97 // Preferences should always have a dictionary root.
145 if (!root->IsType(Value::TYPE_DICTIONARY)) 98 if (!root->IsType(Value::TYPE_DICTIONARY))
146 return false; 99 return false;
147 100
148 persistent_.reset(static_cast<DictionaryValue*>(root.release())); 101 persistent_.reset(static_cast<DictionaryValue*>(root.release()));
149 return true;
150 }
151
152 void PrefService::ReloadPersistentPrefs() {
153 DCHECK(CalledOnValidThread());
154
155 JSONFileValueSerializer serializer(pref_filename_);
156 scoped_ptr<Value> root(serializer.Deserialize(NULL));
157 if (!root.get())
158 return;
159
160 // Preferences should always have a dictionary root.
161 if (!root->IsType(Value::TYPE_DICTIONARY))
162 return;
163
164 persistent_.reset(static_cast<DictionaryValue*>(root.release()));
165 for (PreferenceSet::iterator it = prefs_.begin(); 102 for (PreferenceSet::iterator it = prefs_.begin();
166 it != prefs_.end(); ++it) { 103 it != prefs_.end(); ++it) {
167 (*it)->root_pref_ = persistent_.get(); 104 (*it)->root_pref_ = persistent_.get();
168 } 105 }
169 }
170 106
171 bool PrefService::SavePersistentPrefs(base::Thread* thread) const {
172 DCHECK(!pref_filename_.empty());
173 DCHECK(CalledOnValidThread());
174
175 // TODO(tc): Do we want to prune webkit preferences that match the default
176 // value?
177 std::string data;
178 JSONStringValueSerializer serializer(&data);
179 serializer.set_pretty_print(true);
180 if (!serializer.Serialize(*(persistent_.get())))
181 return false;
182
183 SaveLaterTask* task = new SaveLaterTask(pref_filename_, data);
184 if (thread != NULL) {
185 // We can use the background thread, it will take ownership of the task.
186 thread->message_loop()->PostTask(FROM_HERE, task);
187 } else {
188 // In unit test mode, we have no background thread, just execute.
189 task->Run();
190 delete task;
191 }
192 return true; 107 return true;
193 } 108 }
194 109
195 void PrefService::ScheduleSavePersistentPrefs(base::Thread* thread) { 110 bool PrefService::SavePersistentPrefs() {
196 if (!save_preferences_factory_.empty()) 111 DCHECK(CalledOnValidThread());
197 return;
198 112
199 MessageLoop::current()->PostDelayedTask(FROM_HERE, 113 std::string data;
200 save_preferences_factory_.NewRunnableMethod( 114 if (!SerializePrefData(&data))
201 &PrefService::SavePersistentPrefs, thread), 115 return false;
202 kCommitIntervalMs); 116
117 writer_.WriteNow(data);
118 return true;
119 }
120
121 bool PrefService::ScheduleSavePersistentPrefs() {
122 DCHECK(CalledOnValidThread());
123
124 std::string data;
125 if (!SerializePrefData(&data))
126 return false;
127
128 writer_.ScheduleWrite(data);
129 return true;
203 } 130 }
204 131
205 void PrefService::RegisterBooleanPref(const wchar_t* path, 132 void PrefService::RegisterBooleanPref(const wchar_t* path,
206 bool default_value) { 133 bool default_value) {
207 Preference* pref = new Preference(persistent_.get(), path, 134 Preference* pref = new Preference(persistent_.get(), path,
208 Value::CreateBooleanValue(default_value)); 135 Value::CreateBooleanValue(default_value));
209 RegisterPreference(pref); 136 RegisterPreference(pref);
210 } 137 }
211 138
212 void PrefService::RegisterIntegerPref(const wchar_t* path, 139 void PrefService::RegisterIntegerPref(const wchar_t* path,
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 637
711 NotificationObserverList::Iterator it(*(observer_iterator->second)); 638 NotificationObserverList::Iterator it(*(observer_iterator->second));
712 NotificationObserver* observer; 639 NotificationObserver* observer;
713 while ((observer = it.GetNext()) != NULL) { 640 while ((observer = it.GetNext()) != NULL) {
714 observer->Observe(NotificationType::PREF_CHANGED, 641 observer->Observe(NotificationType::PREF_CHANGED,
715 Source<PrefService>(this), 642 Source<PrefService>(this),
716 Details<std::wstring>(&path_str)); 643 Details<std::wstring>(&path_str));
717 } 644 }
718 } 645 }
719 646
647 bool PrefService::SerializePrefData(std::string* output) const {
648 // TODO(tc): Do we want to prune webkit preferences that match the default
649 // value?
650 JSONStringValueSerializer serializer(output);
651 serializer.set_pretty_print(true);
652 return serializer.Serialize(*(persistent_.get()));
653 }
654
720 /////////////////////////////////////////////////////////////////////////////// 655 ///////////////////////////////////////////////////////////////////////////////
721 // PrefService::Preference 656 // PrefService::Preference
722 657
723 PrefService::Preference::Preference(DictionaryValue* root_pref, 658 PrefService::Preference::Preference(DictionaryValue* root_pref,
724 const wchar_t* name, 659 const wchar_t* name,
725 Value* default_value) 660 Value* default_value)
726 : type_(Value::TYPE_NULL), 661 : type_(Value::TYPE_NULL),
727 name_(name), 662 name_(name),
728 default_value_(default_value), 663 default_value_(default_value),
729 root_pref_(root_pref) { 664 root_pref_(root_pref) {
(...skipping 22 matching lines...) Expand all
752 } 687 }
753 688
754 // Pref not found, just return the app default. 689 // Pref not found, just return the app default.
755 return default_value_.get(); 690 return default_value_.get();
756 } 691 }
757 692
758 bool PrefService::Preference::IsDefaultValue() const { 693 bool PrefService::Preference::IsDefaultValue() const {
759 DCHECK(default_value_.get()); 694 DCHECK(default_value_.get());
760 return default_value_->Equals(GetValue()); 695 return default_value_->Equals(GetValue());
761 } 696 }
OLDNEW
« no previous file with comments | « chrome/common/pref_service.h ('k') | chrome/common/pref_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698