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 |