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

Side by Side Diff: chrome/browser/prefs/tracked/tracked_preferences_migration.cc

Issue 257003007: Introduce a new framework for back-and-forth tracked/protected preferences migration. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: run cleanup directly if destination store wasn't altered (i.e. migration completed in previous run,… Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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/prefs/tracked/tracked_preferences_migration.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/macros.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/prefs/json_pref_store.h"
14 #include "base/values.h"
15
16 namespace {
17
18 class TrackedPreferencesMigrator
19 : public base::RefCounted<TrackedPreferencesMigrator> {
20 public:
21 // Constructs a TrackedPreferencesMigrator which sets itself up as the
22 // OnFileReadInterceptor for both |unprotected_pref_store| and
23 // |protected_pref_store|. It guarantees that the most recent pref value
24 // for |unprotected_pref_names| and |protected_pref_names| are in the
25 // appropriate JsonPrefStores before those stores even sees those values.
26 TrackedPreferencesMigrator(
27 const std::set<std::string>& unprotected_pref_names,
28 const std::set<std::string>& protected_pref_names,
29 JsonPrefStore* unprotected_pref_store,
30 JsonPrefStore* protected_pref_store);
31
32 private:
33 friend class base::RefCounted<TrackedPreferencesMigrator>;
34
35 enum PrefStoreID {
36 UNPROTECTED_PREFERENCE_STORE,
37 PROTECTED_PREFERENCE_STORE
38 };
39
40 ~TrackedPreferencesMigrator();
41
42 // Stores the data coming in for the store identified by |id| into this class
43 // and then calls MigrateIfReady();
44 void OnFileRead(
45 PrefStoreID id,
46 scoped_ptr<base::DictionaryValue> prefs,
47 const JsonPrefStore::FinalizePrefsReadCallback& finalize_prefs_read);
48
49 // Proceeds with migration if both |unprotected_prefs_| and |protected_prefs_|
50 // have been set.
51 void MigrateIfReady();
52
53 const std::set<std::string> unprotected_pref_names_;
54 const std::set<std::string> protected_pref_names_;
55
56 scoped_ptr<base::DictionaryValue> unprotected_prefs_;
57 scoped_ptr<base::DictionaryValue> protected_prefs_;
58
59 JsonPrefStore::FinalizePrefsReadCallback finalize_unprotected_prefs_read_;
60 JsonPrefStore::FinalizePrefsReadCallback finalize_protected_prefs_read_;
61
62 DISALLOW_COPY_AND_ASSIGN(TrackedPreferencesMigrator);
63 };
64
65 // Silently removes all |keys_to_clean| from |pref_store| if the weak pointer is
66 // still valid.
67 void CleanupPrefStore(const base::WeakPtr<JsonPrefStore>& pref_store,
68 const std::set<std::string>& keys_to_clean) {
69 if (pref_store) {
70 for (std::set<std::string>::const_iterator it = keys_to_clean.begin();
71 it != keys_to_clean.end(); ++it) {
72 // Silently clean the values as they have already been copied to their
73 // new authoritative store and we don't want to alert PrefStore observers
74 // about the irrelevant removal of this value which no one should be
75 // reading anymore.
76 pref_store->RemoveValueSilently(*it);
77 }
78 }
79 }
80
81 // If |wait_for_commit_to_destination_store|: schedules a cleanup of the
82 // |keys_to_clean| from the |source_pref_store| once the
83 // |destination_pref_store| they were migrated to was successfully written to
84 // disk. Otherwise, executes the cleanup right away.
85 void ScheduleSourcePrefStoreCleanup(
86 const base::WeakPtr<JsonPrefStore>& source_pref_store,
87 const std::set<std::string>& keys_to_clean,
88 bool wait_for_commit_to_destination_store,
89 JsonPrefStore* destination_pref_store) {
90 DCHECK(source_pref_store);
91 DCHECK(destination_pref_store);
92 DCHECK(!keys_to_clean.empty());
93 if (wait_for_commit_to_destination_store) {
94 destination_pref_store->RegisterOnNextSuccessfulWriteCallback(
95 base::Bind(&CleanupPrefStore, source_pref_store, keys_to_clean));
96 } else {
97 CleanupPrefStore(source_pref_store, keys_to_clean);
98 }
99 }
100
101 // Copies the value of each pref in |pref_names| which is set in |old_store|,
102 // but not in |new_store| into |new_store|. Sets |old_store_needs_cleanup| to
103 // true if any old duplicates remain in |old_store| and sets |new_store_altered|
104 // to true if any value was copied to |new_store|.
105 void MigratePrefsFromOldToNewStore(
106 const std::set<std::string>& pref_names,
107 const base::DictionaryValue* old_store,
108 base::DictionaryValue* new_store,
109 bool* old_store_needs_cleanup,
110 bool* new_store_altered) {
111 for (std::set<std::string>::const_iterator it = pref_names.begin();
112 it != pref_names.end(); ++it) {
113 const std::string& pref_name = *it;
114
115 const base::Value* value_in_old_store = NULL;
116 if (!old_store->Get(pref_name, &value_in_old_store))
117 continue;
118
119 // Whether this value ends up being copied below or was left behind by a
120 // previous incomplete migration, it should be cleaned up.
121 *old_store_needs_cleanup = true;
122
123 if (new_store->Get(pref_name, NULL))
124 continue;
125
126 // Copy the value from |old_store| to |new_store| rather than moving it to
127 // avoid data loss should |old_store| be flushed to disk without |new_store|
128 // having equivalently been successfully flushed to disk (e.g., on crash or
129 // in cases where |new_store| is read-only following a read error on
130 // startup).
131 new_store->Set(pref_name, value_in_old_store->DeepCopy());
132 *new_store_altered = true;
133 }
134 }
135
136 TrackedPreferencesMigrator::TrackedPreferencesMigrator(
137 const std::set<std::string>& unprotected_pref_names,
138 const std::set<std::string>& protected_pref_names,
139 JsonPrefStore* unprotected_pref_store,
140 JsonPrefStore* protected_pref_store)
141 : unprotected_pref_names_(unprotected_pref_names),
142 protected_pref_names_(protected_pref_names) {
143 // The callbacks bound below will own this TrackedPreferencesMigrator by
144 // reference.
145 unprotected_pref_store->InterceptNextFileRead(
146 base::Bind(&TrackedPreferencesMigrator::OnFileRead,
147 this,
148 UNPROTECTED_PREFERENCE_STORE));
149 protected_pref_store->InterceptNextFileRead(
150 base::Bind(&TrackedPreferencesMigrator::OnFileRead,
151 this,
152 PROTECTED_PREFERENCE_STORE));
153 }
154
155 TrackedPreferencesMigrator::~TrackedPreferencesMigrator() {}
156
157 void TrackedPreferencesMigrator::OnFileRead(
158 PrefStoreID id,
159 scoped_ptr<base::DictionaryValue> prefs,
160 const JsonPrefStore::FinalizePrefsReadCallback& finalize_prefs_read) {
161 switch (id) {
162 case UNPROTECTED_PREFERENCE_STORE:
163 unprotected_prefs_ = prefs.Pass();
164 finalize_unprotected_prefs_read_ = finalize_prefs_read;
165 break;
166 case PROTECTED_PREFERENCE_STORE:
167 protected_prefs_ = prefs.Pass();
168 finalize_protected_prefs_read_ = finalize_prefs_read;
169 break;
170 }
171
172 MigrateIfReady();
173 }
174
175 void TrackedPreferencesMigrator::MigrateIfReady() {
176 // Wait for both stores to have been read before proceeding.
177 if (!protected_prefs_ || !unprotected_prefs_)
178 return;
179
180 bool protected_prefs_need_cleanup = false;
181 bool unprotected_prefs_altered = false;
182 MigratePrefsFromOldToNewStore(unprotected_pref_names_,
183 protected_prefs_.get(),
184 unprotected_prefs_.get(),
185 &protected_prefs_need_cleanup,
186 &unprotected_prefs_altered);
187 bool unprotected_prefs_need_cleanup = false;
188 bool protected_prefs_altered = false;
189 MigratePrefsFromOldToNewStore(protected_pref_names_,
190 unprotected_prefs_.get(),
191 protected_prefs_.get(),
192 &unprotected_prefs_need_cleanup,
193 &protected_prefs_altered);
194
195 // Hand the processed prefs back to their respective JsonPrefStore and keep
196 // weak pointers to those stores to make a best effort attempt at cleaning up
197 // duplicate values once those values' destination store was successfully
198 // written to disk.
199 base::WeakPtr<JsonPrefStore> unprotected_pref_store =
Bernhard Bauer 2014/04/30 09:31:05 Hm, this is weird. First of all, why do we need to
gab 2014/04/30 14:32:53 I don't think I have a reference cycle. The weak p
Bernhard Bauer 2014/05/01 12:37:09 You're right, it's not a reference cycle. You are
gab 2014/05/01 15:34:54 True, we could also bound the FinalizeFileReadCall
Bernhard Bauer 2014/05/01 20:16:00 That's true, JsonPrefStore does already survive lo
200 finalize_unprotected_prefs_read_.Run(unprotected_prefs_.Pass(),
201 unprotected_prefs_altered);
202 base::WeakPtr<JsonPrefStore> protected_pref_store =
203 finalize_protected_prefs_read_.Run(protected_prefs_.Pass(),
204 protected_prefs_altered);
205 DCHECK(unprotected_pref_store);
206 DCHECK(protected_pref_store);
gab 2014/04/30 14:32:53 I agree that it's somewhat weird to get the weak p
Bernhard Bauer 2014/05/01 12:37:09 I would not have a problem with that. The usual ob
gab 2014/05/01 15:34:54 (Apologies for the wall of text...) I had initi
Bernhard Bauer 2014/05/01 20:16:00 Heh, I'll respond in kind :)
207
208 if (unprotected_prefs_need_cleanup) {
209 // Cleanup the |protected_pref_names_| from the |unprotected_pref_store|
210 // once they were successfully written to the |protected_pref_store|.
211 ScheduleSourcePrefStoreCleanup(unprotected_pref_store,
212 protected_pref_names_,
213 protected_prefs_altered,
214 protected_pref_store.get());
215 }
216
217 if (protected_prefs_need_cleanup) {
218 // Cleanup the |unprotected_pref_names_| from the |protected_pref_store|
219 // once they were successfully written to the |unprotected_pref_store|.
220 ScheduleSourcePrefStoreCleanup(protected_pref_store,
221 unprotected_pref_names_,
222 unprotected_prefs_altered,
223 unprotected_pref_store.get());
224 }
225 }
226
227 } // namespace
228
229 void SetupTrackedPreferencesMigration(
230 const std::set<std::string>& unprotected_pref_names,
231 const std::set<std::string>& protected_pref_names,
232 JsonPrefStore* unprotected_pref_store,
233 JsonPrefStore* protected_pref_store) {
234 scoped_refptr<TrackedPreferencesMigrator> prefs_migrator(
235 new TrackedPreferencesMigrator(unprotected_pref_names,
236 protected_pref_names,
237 unprotected_pref_store,
238 protected_pref_store));
239 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698