OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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/variations/variations_associated_data.h" |
| 6 |
| 7 #include <map> |
| 8 #include <utility> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/memory/singleton.h" |
| 12 #include "components/variations/metrics_util.h" |
| 13 |
| 14 namespace chrome_variations { |
| 15 |
| 16 namespace { |
| 17 |
| 18 // The internal singleton accessor for the map, used to keep it thread-safe. |
| 19 class GroupMapAccessor { |
| 20 public: |
| 21 typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare> |
| 22 GroupToIDMap; |
| 23 |
| 24 // Retrieve the singleton. |
| 25 static GroupMapAccessor* GetInstance() { |
| 26 return Singleton<GroupMapAccessor>::get(); |
| 27 } |
| 28 |
| 29 // Note that this normally only sets the ID for a group the first time, unless |
| 30 // |force| is set to true, in which case it will always override it. |
| 31 void AssociateID(IDCollectionKey key, |
| 32 const ActiveGroupId& group_identifier, |
| 33 const VariationID id, |
| 34 const bool force) { |
| 35 #if !defined(NDEBUG) |
| 36 // Validate that all collections with this |group_identifier| have the same |
| 37 // associated ID. |
| 38 DCHECK_EQ(2, ID_COLLECTION_COUNT); |
| 39 IDCollectionKey other_key = GOOGLE_WEB_PROPERTIES; |
| 40 if (key == GOOGLE_WEB_PROPERTIES) |
| 41 other_key = GOOGLE_UPDATE_SERVICE; |
| 42 VariationID other_id = GetID(other_key, group_identifier); |
| 43 DCHECK(other_id == EMPTY_ID || other_id == id); |
| 44 #endif |
| 45 |
| 46 base::AutoLock scoped_lock(lock_); |
| 47 |
| 48 GroupToIDMap* group_to_id_map = GetGroupToIDMap(key); |
| 49 if (force || |
| 50 group_to_id_map->find(group_identifier) == group_to_id_map->end()) |
| 51 (*group_to_id_map)[group_identifier] = id; |
| 52 } |
| 53 |
| 54 VariationID GetID(IDCollectionKey key, |
| 55 const ActiveGroupId& group_identifier) { |
| 56 base::AutoLock scoped_lock(lock_); |
| 57 GroupToIDMap* group_to_id_map = GetGroupToIDMap(key); |
| 58 GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier); |
| 59 if (it == group_to_id_map->end()) |
| 60 return EMPTY_ID; |
| 61 return it->second; |
| 62 } |
| 63 |
| 64 void ClearAllMapsForTesting() { |
| 65 base::AutoLock scoped_lock(lock_); |
| 66 |
| 67 for (int i = 0; i < ID_COLLECTION_COUNT; ++i) { |
| 68 GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i)); |
| 69 DCHECK(map); |
| 70 map->clear(); |
| 71 } |
| 72 } |
| 73 |
| 74 private: |
| 75 friend struct DefaultSingletonTraits<GroupMapAccessor>; |
| 76 |
| 77 // Retrieves the GroupToIDMap for |key|. |
| 78 GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) { |
| 79 return &group_to_id_maps_[key]; |
| 80 } |
| 81 |
| 82 GroupMapAccessor() { |
| 83 group_to_id_maps_.resize(ID_COLLECTION_COUNT); |
| 84 } |
| 85 ~GroupMapAccessor() {} |
| 86 |
| 87 base::Lock lock_; |
| 88 std::vector<GroupToIDMap> group_to_id_maps_; |
| 89 |
| 90 DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor); |
| 91 }; |
| 92 |
| 93 // Singleton helper class that keeps track of the parameters of all variations |
| 94 // and ensures access to these is thread-safe. |
| 95 class VariationsParamAssociator { |
| 96 public: |
| 97 typedef std::pair<std::string, std::string> VariationKey; |
| 98 typedef std::map<std::string, std::string> VariationParams; |
| 99 |
| 100 // Retrieve the singleton. |
| 101 static VariationsParamAssociator* GetInstance() { |
| 102 return Singleton<VariationsParamAssociator>::get(); |
| 103 } |
| 104 |
| 105 bool AssociateVariationParams(const std::string& trial_name, |
| 106 const std::string& group_name, |
| 107 const VariationParams& params) { |
| 108 base::AutoLock scoped_lock(lock_); |
| 109 |
| 110 if (IsFieldTrialActive(trial_name)) |
| 111 return false; |
| 112 |
| 113 const VariationKey key(trial_name, group_name); |
| 114 if (ContainsKey(variation_params_, key)) |
| 115 return false; |
| 116 |
| 117 variation_params_[key] = params; |
| 118 return true; |
| 119 } |
| 120 |
| 121 bool GetVariationParams(const std::string& trial_name, |
| 122 VariationParams* params) { |
| 123 base::AutoLock scoped_lock(lock_); |
| 124 |
| 125 const std::string group_name = |
| 126 base::FieldTrialList::FindFullName(trial_name); |
| 127 const VariationKey key(trial_name, group_name); |
| 128 if (!ContainsKey(variation_params_, key)) |
| 129 return false; |
| 130 |
| 131 *params = variation_params_[key]; |
| 132 return true; |
| 133 } |
| 134 |
| 135 void ClearAllParamsForTesting() { |
| 136 base::AutoLock scoped_lock(lock_); |
| 137 variation_params_.clear(); |
| 138 } |
| 139 |
| 140 private: |
| 141 friend struct DefaultSingletonTraits<VariationsParamAssociator>; |
| 142 |
| 143 VariationsParamAssociator() {} |
| 144 ~VariationsParamAssociator() {} |
| 145 |
| 146 // Tests whether a field trial is active (i.e. group() has been called on it). |
| 147 // TODO(asvitkine): Expose this as an API on base::FieldTrial. |
| 148 bool IsFieldTrialActive(const std::string& trial_name) { |
| 149 base::FieldTrial::ActiveGroups active_groups; |
| 150 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups); |
| 151 for (size_t i = 0; i < active_groups.size(); ++i) { |
| 152 if (active_groups[i].trial_name == trial_name) |
| 153 return true; |
| 154 } |
| 155 return false; |
| 156 } |
| 157 |
| 158 base::Lock lock_; |
| 159 std::map<VariationKey, VariationParams> variation_params_; |
| 160 |
| 161 DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator); |
| 162 }; |
| 163 |
| 164 } // namespace |
| 165 |
| 166 ActiveGroupId MakeActiveGroupId(const std::string& trial_name, |
| 167 const std::string& group_name) { |
| 168 ActiveGroupId id; |
| 169 id.name = metrics::HashName(trial_name); |
| 170 id.group = metrics::HashName(group_name); |
| 171 return id; |
| 172 } |
| 173 |
| 174 void AssociateGoogleVariationID(IDCollectionKey key, |
| 175 const std::string& trial_name, |
| 176 const std::string& group_name, |
| 177 VariationID id) { |
| 178 GroupMapAccessor::GetInstance()->AssociateID( |
| 179 key, MakeActiveGroupId(trial_name, group_name), id, false); |
| 180 } |
| 181 |
| 182 void AssociateGoogleVariationIDForce(IDCollectionKey key, |
| 183 const std::string& trial_name, |
| 184 const std::string& group_name, |
| 185 VariationID id) { |
| 186 GroupMapAccessor::GetInstance()->AssociateID( |
| 187 key, MakeActiveGroupId(trial_name, group_name), id, true); |
| 188 } |
| 189 |
| 190 VariationID GetGoogleVariationID(IDCollectionKey key, |
| 191 const std::string& trial_name, |
| 192 const std::string& group_name) { |
| 193 return GroupMapAccessor::GetInstance()->GetID( |
| 194 key, MakeActiveGroupId(trial_name, group_name)); |
| 195 } |
| 196 |
| 197 bool AssociateVariationParams( |
| 198 const std::string& trial_name, |
| 199 const std::string& group_name, |
| 200 const std::map<std::string, std::string>& params) { |
| 201 return VariationsParamAssociator::GetInstance()->AssociateVariationParams( |
| 202 trial_name, group_name, params); |
| 203 } |
| 204 |
| 205 bool GetVariationParams(const std::string& trial_name, |
| 206 std::map<std::string, std::string>* params) { |
| 207 return VariationsParamAssociator::GetInstance()->GetVariationParams( |
| 208 trial_name, params); |
| 209 } |
| 210 |
| 211 std::string GetVariationParamValue(const std::string& trial_name, |
| 212 const std::string& param_name) { |
| 213 std::map<std::string, std::string> params; |
| 214 if (GetVariationParams(trial_name, ¶ms)) { |
| 215 std::map<std::string, std::string>::iterator it = params.find(param_name); |
| 216 if (it != params.end()) |
| 217 return it->second; |
| 218 } |
| 219 return std::string(); |
| 220 } |
| 221 |
| 222 // Functions below are exposed for testing explicitly behind this namespace. |
| 223 // They simply wrap existing functions in this file. |
| 224 namespace testing { |
| 225 |
| 226 void ClearAllVariationIDs() { |
| 227 GroupMapAccessor::GetInstance()->ClearAllMapsForTesting(); |
| 228 } |
| 229 |
| 230 void ClearAllVariationParams() { |
| 231 VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting(); |
| 232 } |
| 233 |
| 234 } // namespace testing |
| 235 |
| 236 } // namespace chrome_variations |
OLD | NEW |