| 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 "chrome/common/metrics/variations/variations_associated_data.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/memory/singleton.h" | |
| 11 #include "chrome/common/metrics/metrics_util.h" | |
| 12 #include "chrome/common/metrics/variations/variation_ids.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 |