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"
13 namespace chrome_variations
{
15 // TODO(asvitkine): Delete these when this file moves to variations namespace.
16 using variations::ActiveGroupId
;
17 using variations::ActiveGroupIdCompare
;
18 using variations::MakeActiveGroupId
;
22 // The internal singleton accessor for the map, used to keep it thread-safe.
23 class GroupMapAccessor
{
25 typedef std::map
<ActiveGroupId
, VariationID
, ActiveGroupIdCompare
>
28 // Retrieve the singleton.
29 static GroupMapAccessor
* GetInstance() {
30 return Singleton
<GroupMapAccessor
>::get();
33 // Note that this normally only sets the ID for a group the first time, unless
34 // |force| is set to true, in which case it will always override it.
35 void AssociateID(IDCollectionKey key
,
36 const ActiveGroupId
& group_identifier
,
40 DCHECK_EQ(3, ID_COLLECTION_COUNT
);
41 // Ensure that at most one of the trigger/non-trigger web property IDs are
43 if (key
== GOOGLE_WEB_PROPERTIES
|| key
== GOOGLE_WEB_PROPERTIES_TRIGGER
) {
44 IDCollectionKey other_key
= key
== GOOGLE_WEB_PROPERTIES
?
45 GOOGLE_WEB_PROPERTIES_TRIGGER
: GOOGLE_WEB_PROPERTIES
;
46 DCHECK_EQ(EMPTY_ID
, GetID(other_key
, group_identifier
));
49 // Validate that all collections with this |group_identifier| have the same
51 for (int i
= 0; i
< ID_COLLECTION_COUNT
; ++i
) {
52 IDCollectionKey other_key
= static_cast<IDCollectionKey
>(i
);
55 VariationID other_id
= GetID(other_key
, group_identifier
);
56 DCHECK(other_id
== EMPTY_ID
|| other_id
== id
);
60 base::AutoLock
scoped_lock(lock_
);
62 GroupToIDMap
* group_to_id_map
= GetGroupToIDMap(key
);
64 group_to_id_map
->find(group_identifier
) == group_to_id_map
->end())
65 (*group_to_id_map
)[group_identifier
] = id
;
68 VariationID
GetID(IDCollectionKey key
,
69 const ActiveGroupId
& group_identifier
) {
70 base::AutoLock
scoped_lock(lock_
);
71 GroupToIDMap
* group_to_id_map
= GetGroupToIDMap(key
);
72 GroupToIDMap::const_iterator it
= group_to_id_map
->find(group_identifier
);
73 if (it
== group_to_id_map
->end())
78 void ClearAllMapsForTesting() {
79 base::AutoLock
scoped_lock(lock_
);
81 for (int i
= 0; i
< ID_COLLECTION_COUNT
; ++i
) {
82 GroupToIDMap
* map
= GetGroupToIDMap(static_cast<IDCollectionKey
>(i
));
89 friend struct DefaultSingletonTraits
<GroupMapAccessor
>;
91 // Retrieves the GroupToIDMap for |key|.
92 GroupToIDMap
* GetGroupToIDMap(IDCollectionKey key
) {
93 return &group_to_id_maps_
[key
];
97 group_to_id_maps_
.resize(ID_COLLECTION_COUNT
);
99 ~GroupMapAccessor() {}
102 std::vector
<GroupToIDMap
> group_to_id_maps_
;
104 DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor
);
107 // Singleton helper class that keeps track of the parameters of all variations
108 // and ensures access to these is thread-safe.
109 class VariationsParamAssociator
{
111 typedef std::pair
<std::string
, std::string
> VariationKey
;
112 typedef std::map
<std::string
, std::string
> VariationParams
;
114 // Retrieve the singleton.
115 static VariationsParamAssociator
* GetInstance() {
116 return Singleton
<VariationsParamAssociator
>::get();
119 bool AssociateVariationParams(const std::string
& trial_name
,
120 const std::string
& group_name
,
121 const VariationParams
& params
) {
122 base::AutoLock
scoped_lock(lock_
);
124 if (IsFieldTrialActive(trial_name
))
127 const VariationKey
key(trial_name
, group_name
);
128 if (ContainsKey(variation_params_
, key
))
131 variation_params_
[key
] = params
;
135 bool GetVariationParams(const std::string
& trial_name
,
136 VariationParams
* params
) {
137 base::AutoLock
scoped_lock(lock_
);
139 const std::string group_name
=
140 base::FieldTrialList::FindFullName(trial_name
);
141 const VariationKey
key(trial_name
, group_name
);
142 if (!ContainsKey(variation_params_
, key
))
145 *params
= variation_params_
[key
];
149 void ClearAllParamsForTesting() {
150 base::AutoLock
scoped_lock(lock_
);
151 variation_params_
.clear();
155 friend struct DefaultSingletonTraits
<VariationsParamAssociator
>;
157 VariationsParamAssociator() {}
158 ~VariationsParamAssociator() {}
160 // Tests whether a field trial is active (i.e. group() has been called on it).
161 // TODO(asvitkine): Expose this as an API on base::FieldTrial.
162 bool IsFieldTrialActive(const std::string
& trial_name
) {
163 base::FieldTrial::ActiveGroups active_groups
;
164 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
165 for (size_t i
= 0; i
< active_groups
.size(); ++i
) {
166 if (active_groups
[i
].trial_name
== trial_name
)
173 std::map
<VariationKey
, VariationParams
> variation_params_
;
175 DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator
);
180 void AssociateGoogleVariationID(IDCollectionKey key
,
181 const std::string
& trial_name
,
182 const std::string
& group_name
,
184 GroupMapAccessor::GetInstance()->AssociateID(
185 key
, MakeActiveGroupId(trial_name
, group_name
), id
, false);
188 void AssociateGoogleVariationIDForce(IDCollectionKey key
,
189 const std::string
& trial_name
,
190 const std::string
& group_name
,
192 GroupMapAccessor::GetInstance()->AssociateID(
193 key
, MakeActiveGroupId(trial_name
, group_name
), id
, true);
196 VariationID
GetGoogleVariationID(IDCollectionKey key
,
197 const std::string
& trial_name
,
198 const std::string
& group_name
) {
199 return GroupMapAccessor::GetInstance()->GetID(
200 key
, MakeActiveGroupId(trial_name
, group_name
));
203 bool AssociateVariationParams(
204 const std::string
& trial_name
,
205 const std::string
& group_name
,
206 const std::map
<std::string
, std::string
>& params
) {
207 return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
208 trial_name
, group_name
, params
);
211 bool GetVariationParams(const std::string
& trial_name
,
212 std::map
<std::string
, std::string
>* params
) {
213 return VariationsParamAssociator::GetInstance()->GetVariationParams(
217 std::string
GetVariationParamValue(const std::string
& trial_name
,
218 const std::string
& param_name
) {
219 std::map
<std::string
, std::string
> params
;
220 if (GetVariationParams(trial_name
, ¶ms
)) {
221 std::map
<std::string
, std::string
>::iterator it
= params
.find(param_name
);
222 if (it
!= params
.end())
225 return std::string();
228 // Functions below are exposed for testing explicitly behind this namespace.
229 // They simply wrap existing functions in this file.
232 void ClearAllVariationIDs() {
233 GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
236 void ClearAllVariationParams() {
237 VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
240 } // namespace testing
242 } // namespace chrome_variations