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.
5 #include "components/variations/variations_associated_data.h"
11 #include "base/memory/singleton.h"
12 #include "components/variations/metrics_util.h"
14 namespace chrome_variations {
18 // The internal singleton accessor for the map, used to keep it thread-safe.
19 class GroupMapAccessor {
21 typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
24 // Retrieve the singleton.
25 static GroupMapAccessor* GetInstance() {
26 return Singleton<GroupMapAccessor>::get();
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,
36 DCHECK_EQ(3, ID_COLLECTION_COUNT);
37 // Ensure that at most one of the trigger/non-trigger web property IDs are
39 if (key == GOOGLE_WEB_PROPERTIES || key == GOOGLE_WEB_PROPERTIES_TRIGGER) {
40 IDCollectionKey other_key = key == GOOGLE_WEB_PROPERTIES ?
41 GOOGLE_WEB_PROPERTIES_TRIGGER : GOOGLE_WEB_PROPERTIES;
42 DCHECK_EQ(EMPTY_ID, GetID(other_key, group_identifier));
45 // Validate that all collections with this |group_identifier| have the same
47 for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
48 IDCollectionKey other_key = static_cast<IDCollectionKey>(i);
51 VariationID other_id = GetID(other_key, group_identifier);
52 DCHECK(other_id == EMPTY_ID || other_id == id);
56 base::AutoLock scoped_lock(lock_);
58 GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
60 group_to_id_map->find(group_identifier) == group_to_id_map->end())
61 (*group_to_id_map)[group_identifier] = id;
64 VariationID GetID(IDCollectionKey key,
65 const ActiveGroupId& group_identifier) {
66 base::AutoLock scoped_lock(lock_);
67 GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
68 GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier);
69 if (it == group_to_id_map->end())
74 void ClearAllMapsForTesting() {
75 base::AutoLock scoped_lock(lock_);
77 for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
78 GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i));
85 friend struct DefaultSingletonTraits<GroupMapAccessor>;
87 // Retrieves the GroupToIDMap for |key|.
88 GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
89 return &group_to_id_maps_[key];
93 group_to_id_maps_.resize(ID_COLLECTION_COUNT);
95 ~GroupMapAccessor() {}
98 std::vector<GroupToIDMap> group_to_id_maps_;
100 DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor);
103 // Singleton helper class that keeps track of the parameters of all variations
104 // and ensures access to these is thread-safe.
105 class VariationsParamAssociator {
107 typedef std::pair<std::string, std::string> VariationKey;
108 typedef std::map<std::string, std::string> VariationParams;
110 // Retrieve the singleton.
111 static VariationsParamAssociator* GetInstance() {
112 return Singleton<VariationsParamAssociator>::get();
115 bool AssociateVariationParams(const std::string& trial_name,
116 const std::string& group_name,
117 const VariationParams& params) {
118 base::AutoLock scoped_lock(lock_);
120 if (IsFieldTrialActive(trial_name))
123 const VariationKey key(trial_name, group_name);
124 if (ContainsKey(variation_params_, key))
127 variation_params_[key] = params;
131 bool GetVariationParams(const std::string& trial_name,
132 VariationParams* params) {
133 base::AutoLock scoped_lock(lock_);
135 const std::string group_name =
136 base::FieldTrialList::FindFullName(trial_name);
137 const VariationKey key(trial_name, group_name);
138 if (!ContainsKey(variation_params_, key))
141 *params = variation_params_[key];
145 void ClearAllParamsForTesting() {
146 base::AutoLock scoped_lock(lock_);
147 variation_params_.clear();
151 friend struct DefaultSingletonTraits<VariationsParamAssociator>;
153 VariationsParamAssociator() {}
154 ~VariationsParamAssociator() {}
156 // Tests whether a field trial is active (i.e. group() has been called on it).
157 // TODO(asvitkine): Expose this as an API on base::FieldTrial.
158 bool IsFieldTrialActive(const std::string& trial_name) {
159 base::FieldTrial::ActiveGroups active_groups;
160 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
161 for (size_t i = 0; i < active_groups.size(); ++i) {
162 if (active_groups[i].trial_name == trial_name)
169 std::map<VariationKey, VariationParams> variation_params_;
171 DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
176 ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
177 const std::string& group_name) {
179 id.name = metrics::HashName(trial_name);
180 id.group = metrics::HashName(group_name);
184 void AssociateGoogleVariationID(IDCollectionKey key,
185 const std::string& trial_name,
186 const std::string& group_name,
188 GroupMapAccessor::GetInstance()->AssociateID(
189 key, MakeActiveGroupId(trial_name, group_name), id, false);
192 void AssociateGoogleVariationIDForce(IDCollectionKey key,
193 const std::string& trial_name,
194 const std::string& group_name,
196 GroupMapAccessor::GetInstance()->AssociateID(
197 key, MakeActiveGroupId(trial_name, group_name), id, true);
200 VariationID GetGoogleVariationID(IDCollectionKey key,
201 const std::string& trial_name,
202 const std::string& group_name) {
203 return GroupMapAccessor::GetInstance()->GetID(
204 key, MakeActiveGroupId(trial_name, group_name));
207 bool AssociateVariationParams(
208 const std::string& trial_name,
209 const std::string& group_name,
210 const std::map<std::string, std::string>& params) {
211 return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
212 trial_name, group_name, params);
215 bool GetVariationParams(const std::string& trial_name,
216 std::map<std::string, std::string>* params) {
217 return VariationsParamAssociator::GetInstance()->GetVariationParams(
221 std::string GetVariationParamValue(const std::string& trial_name,
222 const std::string& param_name) {
223 std::map<std::string, std::string> params;
224 if (GetVariationParams(trial_name, ¶ms)) {
225 std::map<std::string, std::string>::iterator it = params.find(param_name);
226 if (it != params.end())
229 return std::string();
232 // Functions below are exposed for testing explicitly behind this namespace.
233 // They simply wrap existing functions in this file.
236 void ClearAllVariationIDs() {
237 GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
240 void ClearAllVariationParams() {
241 VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
244 } // namespace testing
246 } // namespace chrome_variations