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 variations
{
17 // The internal singleton accessor for the map, used to keep it thread-safe.
18 class GroupMapAccessor
{
20 typedef std::map
<ActiveGroupId
, VariationID
, ActiveGroupIdCompare
>
23 // Retrieve the singleton.
24 static GroupMapAccessor
* GetInstance() {
25 return base::Singleton
<GroupMapAccessor
>::get();
28 // Note that this normally only sets the ID for a group the first time, unless
29 // |force| is set to true, in which case it will always override it.
30 void AssociateID(IDCollectionKey key
,
31 const ActiveGroupId
& group_identifier
,
35 DCHECK_EQ(4, ID_COLLECTION_COUNT
);
36 // Ensure that at most one of the trigger/non-trigger web property IDs are
38 if (key
== GOOGLE_WEB_PROPERTIES
|| key
== GOOGLE_WEB_PROPERTIES_TRIGGER
) {
39 IDCollectionKey other_key
= key
== GOOGLE_WEB_PROPERTIES
?
40 GOOGLE_WEB_PROPERTIES_TRIGGER
: GOOGLE_WEB_PROPERTIES
;
41 DCHECK_EQ(EMPTY_ID
, GetID(other_key
, group_identifier
));
44 // Validate that all collections with this |group_identifier| have the same
46 for (int i
= 0; i
< ID_COLLECTION_COUNT
; ++i
) {
47 IDCollectionKey other_key
= static_cast<IDCollectionKey
>(i
);
50 VariationID other_id
= GetID(other_key
, group_identifier
);
51 DCHECK(other_id
== EMPTY_ID
|| other_id
== id
);
55 base::AutoLock
scoped_lock(lock_
);
57 GroupToIDMap
* group_to_id_map
= GetGroupToIDMap(key
);
59 group_to_id_map
->find(group_identifier
) == group_to_id_map
->end())
60 (*group_to_id_map
)[group_identifier
] = id
;
63 VariationID
GetID(IDCollectionKey key
,
64 const ActiveGroupId
& group_identifier
) {
65 base::AutoLock
scoped_lock(lock_
);
66 GroupToIDMap
* group_to_id_map
= GetGroupToIDMap(key
);
67 GroupToIDMap::const_iterator it
= group_to_id_map
->find(group_identifier
);
68 if (it
== group_to_id_map
->end())
73 void ClearAllMapsForTesting() {
74 base::AutoLock
scoped_lock(lock_
);
76 for (int i
= 0; i
< ID_COLLECTION_COUNT
; ++i
) {
77 GroupToIDMap
* map
= GetGroupToIDMap(static_cast<IDCollectionKey
>(i
));
84 friend struct base::DefaultSingletonTraits
<GroupMapAccessor
>;
86 // Retrieves the GroupToIDMap for |key|.
87 GroupToIDMap
* GetGroupToIDMap(IDCollectionKey key
) {
88 return &group_to_id_maps_
[key
];
92 group_to_id_maps_
.resize(ID_COLLECTION_COUNT
);
94 ~GroupMapAccessor() {}
97 std::vector
<GroupToIDMap
> group_to_id_maps_
;
99 DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor
);
102 // Singleton helper class that keeps track of the parameters of all variations
103 // and ensures access to these is thread-safe.
104 class VariationsParamAssociator
{
106 typedef std::pair
<std::string
, std::string
> VariationKey
;
107 typedef std::map
<std::string
, std::string
> VariationParams
;
109 // Retrieve the singleton.
110 static VariationsParamAssociator
* GetInstance() {
111 return base::Singleton
<VariationsParamAssociator
>::get();
114 bool AssociateVariationParams(const std::string
& trial_name
,
115 const std::string
& group_name
,
116 const VariationParams
& params
) {
117 base::AutoLock
scoped_lock(lock_
);
119 if (IsFieldTrialActive(trial_name
))
122 const VariationKey
key(trial_name
, group_name
);
123 if (ContainsKey(variation_params_
, key
))
126 variation_params_
[key
] = params
;
130 bool GetVariationParams(const std::string
& trial_name
,
131 VariationParams
* params
) {
132 base::AutoLock
scoped_lock(lock_
);
134 const std::string group_name
=
135 base::FieldTrialList::FindFullName(trial_name
);
136 const VariationKey
key(trial_name
, group_name
);
137 if (!ContainsKey(variation_params_
, key
))
140 *params
= variation_params_
[key
];
144 void ClearAllParamsForTesting() {
145 base::AutoLock
scoped_lock(lock_
);
146 variation_params_
.clear();
150 friend struct base::DefaultSingletonTraits
<VariationsParamAssociator
>;
152 VariationsParamAssociator() {}
153 ~VariationsParamAssociator() {}
155 // Tests whether a field trial is active (i.e. group() has been called on it).
156 // TODO(asvitkine): Expose this as an API on base::FieldTrial.
157 bool IsFieldTrialActive(const std::string
& trial_name
) {
158 base::FieldTrial::ActiveGroups active_groups
;
159 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups
);
160 for (size_t i
= 0; i
< active_groups
.size(); ++i
) {
161 if (active_groups
[i
].trial_name
== trial_name
)
168 std::map
<VariationKey
, VariationParams
> variation_params_
;
170 DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator
);
175 void AssociateGoogleVariationID(IDCollectionKey key
,
176 const std::string
& trial_name
,
177 const std::string
& group_name
,
179 GroupMapAccessor::GetInstance()->AssociateID(
180 key
, MakeActiveGroupId(trial_name
, group_name
), id
, false);
183 void AssociateGoogleVariationIDForce(IDCollectionKey key
,
184 const std::string
& trial_name
,
185 const std::string
& group_name
,
187 AssociateGoogleVariationIDForceHashes(
188 key
, MakeActiveGroupId(trial_name
, group_name
), id
);
191 void AssociateGoogleVariationIDForceHashes(IDCollectionKey key
,
192 const ActiveGroupId
& active_group
,
194 GroupMapAccessor::GetInstance()->AssociateID(key
, active_group
, id
, true);
197 VariationID
GetGoogleVariationID(IDCollectionKey key
,
198 const std::string
& trial_name
,
199 const std::string
& group_name
) {
200 return GetGoogleVariationIDFromHashes(
201 key
, MakeActiveGroupId(trial_name
, group_name
));
204 VariationID
GetGoogleVariationIDFromHashes(
206 const ActiveGroupId
& active_group
) {
207 return GroupMapAccessor::GetInstance()->GetID(key
, active_group
);
210 bool AssociateVariationParams(
211 const std::string
& trial_name
,
212 const std::string
& group_name
,
213 const std::map
<std::string
, std::string
>& params
) {
214 return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
215 trial_name
, group_name
, params
);
218 bool GetVariationParams(const std::string
& trial_name
,
219 std::map
<std::string
, std::string
>* params
) {
220 return VariationsParamAssociator::GetInstance()->GetVariationParams(
224 std::string
GetVariationParamValue(const std::string
& trial_name
,
225 const std::string
& param_name
) {
226 std::map
<std::string
, std::string
> params
;
227 if (GetVariationParams(trial_name
, ¶ms
)) {
228 std::map
<std::string
, std::string
>::iterator it
= params
.find(param_name
);
229 if (it
!= params
.end())
232 return std::string();
235 // Functions below are exposed for testing explicitly behind this namespace.
236 // They simply wrap existing functions in this file.
239 void ClearAllVariationIDs() {
240 GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
243 void ClearAllVariationParams() {
244 VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
247 } // namespace testing
249 } // namespace variations