Fix Up SingletonHwnd Observer Lifetime Issues
[chromium-blink-merge.git] / components / variations / variations_associated_data.cc
bloba26470438fb2cc3fd69acd89a336e9c5c33d750f
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"
7 #include <map>
8 #include <utility>
9 #include <vector>
11 #include "base/memory/singleton.h"
13 namespace variations {
15 namespace {
17 // The internal singleton accessor for the map, used to keep it thread-safe.
18 class GroupMapAccessor {
19 public:
20 typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
21 GroupToIDMap;
23 // Retrieve the singleton.
24 static GroupMapAccessor* GetInstance() {
25 return 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,
32 const VariationID id,
33 const bool force) {
34 #if !defined(NDEBUG)
35 DCHECK_EQ(4, ID_COLLECTION_COUNT);
36 // Ensure that at most one of the trigger/non-trigger web property IDs are
37 // set.
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
45 // associated ID.
46 for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
47 IDCollectionKey other_key = static_cast<IDCollectionKey>(i);
48 if (other_key == key)
49 continue;
50 VariationID other_id = GetID(other_key, group_identifier);
51 DCHECK(other_id == EMPTY_ID || other_id == id);
53 #endif
55 base::AutoLock scoped_lock(lock_);
57 GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
58 if (force ||
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())
69 return EMPTY_ID;
70 return it->second;
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));
78 DCHECK(map);
79 map->clear();
83 private:
84 friend struct DefaultSingletonTraits<GroupMapAccessor>;
86 // Retrieves the GroupToIDMap for |key|.
87 GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
88 return &group_to_id_maps_[key];
91 GroupMapAccessor() {
92 group_to_id_maps_.resize(ID_COLLECTION_COUNT);
94 ~GroupMapAccessor() {}
96 base::Lock lock_;
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 {
105 public:
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 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))
120 return false;
122 const VariationKey key(trial_name, group_name);
123 if (ContainsKey(variation_params_, key))
124 return false;
126 variation_params_[key] = params;
127 return true;
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))
138 return false;
140 *params = variation_params_[key];
141 return true;
144 void ClearAllParamsForTesting() {
145 base::AutoLock scoped_lock(lock_);
146 variation_params_.clear();
149 private:
150 friend struct 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)
162 return true;
164 return false;
167 base::Lock lock_;
168 std::map<VariationKey, VariationParams> variation_params_;
170 DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
173 } // namespace
175 void AssociateGoogleVariationID(IDCollectionKey key,
176 const std::string& trial_name,
177 const std::string& group_name,
178 VariationID id) {
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,
186 VariationID id) {
187 AssociateGoogleVariationIDForceHashes(
188 key, MakeActiveGroupId(trial_name, group_name), id);
191 void AssociateGoogleVariationIDForceHashes(IDCollectionKey key,
192 const ActiveGroupId& active_group,
193 VariationID id) {
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(
205 IDCollectionKey key,
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(
221 trial_name, params);
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, &params)) {
228 std::map<std::string, std::string>::iterator it = params.find(param_name);
229 if (it != params.end())
230 return it->second;
232 return std::string();
235 // Functions below are exposed for testing explicitly behind this namespace.
236 // They simply wrap existing functions in this file.
237 namespace testing {
239 void ClearAllVariationIDs() {
240 GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
243 void ClearAllVariationParams() {
244 VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
247 } // namespace testing
249 } // namespace variations