Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 } | |
| OLD | NEW |