| Index: components/variations/variations_associated_data.cc
|
| ===================================================================
|
| --- components/variations/variations_associated_data.cc (revision 0)
|
| +++ components/variations/variations_associated_data.cc (working copy)
|
| @@ -0,0 +1,236 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "components/variations/variations_associated_data.h"
|
| +
|
| +#include <map>
|
| +#include <utility>
|
| +#include <vector>
|
| +
|
| +#include "base/memory/singleton.h"
|
| +#include "components/variations/metrics_util.h"
|
| +
|
| +namespace chrome_variations {
|
| +
|
| +namespace {
|
| +
|
| +// The internal singleton accessor for the map, used to keep it thread-safe.
|
| +class GroupMapAccessor {
|
| + public:
|
| + typedef std::map<ActiveGroupId, VariationID, ActiveGroupIdCompare>
|
| + GroupToIDMap;
|
| +
|
| + // Retrieve the singleton.
|
| + static GroupMapAccessor* GetInstance() {
|
| + return Singleton<GroupMapAccessor>::get();
|
| + }
|
| +
|
| + // Note that this normally only sets the ID for a group the first time, unless
|
| + // |force| is set to true, in which case it will always override it.
|
| + void AssociateID(IDCollectionKey key,
|
| + const ActiveGroupId& group_identifier,
|
| + const VariationID id,
|
| + const bool force) {
|
| +#if !defined(NDEBUG)
|
| + // Validate that all collections with this |group_identifier| have the same
|
| + // associated ID.
|
| + DCHECK_EQ(2, ID_COLLECTION_COUNT);
|
| + IDCollectionKey other_key = GOOGLE_WEB_PROPERTIES;
|
| + if (key == GOOGLE_WEB_PROPERTIES)
|
| + other_key = GOOGLE_UPDATE_SERVICE;
|
| + VariationID other_id = GetID(other_key, group_identifier);
|
| + DCHECK(other_id == EMPTY_ID || other_id == id);
|
| +#endif
|
| +
|
| + base::AutoLock scoped_lock(lock_);
|
| +
|
| + GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
|
| + if (force ||
|
| + group_to_id_map->find(group_identifier) == group_to_id_map->end())
|
| + (*group_to_id_map)[group_identifier] = id;
|
| + }
|
| +
|
| + VariationID GetID(IDCollectionKey key,
|
| + const ActiveGroupId& group_identifier) {
|
| + base::AutoLock scoped_lock(lock_);
|
| + GroupToIDMap* group_to_id_map = GetGroupToIDMap(key);
|
| + GroupToIDMap::const_iterator it = group_to_id_map->find(group_identifier);
|
| + if (it == group_to_id_map->end())
|
| + return EMPTY_ID;
|
| + return it->second;
|
| + }
|
| +
|
| + void ClearAllMapsForTesting() {
|
| + base::AutoLock scoped_lock(lock_);
|
| +
|
| + for (int i = 0; i < ID_COLLECTION_COUNT; ++i) {
|
| + GroupToIDMap* map = GetGroupToIDMap(static_cast<IDCollectionKey>(i));
|
| + DCHECK(map);
|
| + map->clear();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + friend struct DefaultSingletonTraits<GroupMapAccessor>;
|
| +
|
| + // Retrieves the GroupToIDMap for |key|.
|
| + GroupToIDMap* GetGroupToIDMap(IDCollectionKey key) {
|
| + return &group_to_id_maps_[key];
|
| + }
|
| +
|
| + GroupMapAccessor() {
|
| + group_to_id_maps_.resize(ID_COLLECTION_COUNT);
|
| + }
|
| + ~GroupMapAccessor() {}
|
| +
|
| + base::Lock lock_;
|
| + std::vector<GroupToIDMap> group_to_id_maps_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(GroupMapAccessor);
|
| +};
|
| +
|
| +// Singleton helper class that keeps track of the parameters of all variations
|
| +// and ensures access to these is thread-safe.
|
| +class VariationsParamAssociator {
|
| + public:
|
| + typedef std::pair<std::string, std::string> VariationKey;
|
| + typedef std::map<std::string, std::string> VariationParams;
|
| +
|
| + // Retrieve the singleton.
|
| + static VariationsParamAssociator* GetInstance() {
|
| + return Singleton<VariationsParamAssociator>::get();
|
| + }
|
| +
|
| + bool AssociateVariationParams(const std::string& trial_name,
|
| + const std::string& group_name,
|
| + const VariationParams& params) {
|
| + base::AutoLock scoped_lock(lock_);
|
| +
|
| + if (IsFieldTrialActive(trial_name))
|
| + return false;
|
| +
|
| + const VariationKey key(trial_name, group_name);
|
| + if (ContainsKey(variation_params_, key))
|
| + return false;
|
| +
|
| + variation_params_[key] = params;
|
| + return true;
|
| + }
|
| +
|
| + bool GetVariationParams(const std::string& trial_name,
|
| + VariationParams* params) {
|
| + base::AutoLock scoped_lock(lock_);
|
| +
|
| + const std::string group_name =
|
| + base::FieldTrialList::FindFullName(trial_name);
|
| + const VariationKey key(trial_name, group_name);
|
| + if (!ContainsKey(variation_params_, key))
|
| + return false;
|
| +
|
| + *params = variation_params_[key];
|
| + return true;
|
| + }
|
| +
|
| + void ClearAllParamsForTesting() {
|
| + base::AutoLock scoped_lock(lock_);
|
| + variation_params_.clear();
|
| + }
|
| +
|
| + private:
|
| + friend struct DefaultSingletonTraits<VariationsParamAssociator>;
|
| +
|
| + VariationsParamAssociator() {}
|
| + ~VariationsParamAssociator() {}
|
| +
|
| + // Tests whether a field trial is active (i.e. group() has been called on it).
|
| + // TODO(asvitkine): Expose this as an API on base::FieldTrial.
|
| + bool IsFieldTrialActive(const std::string& trial_name) {
|
| + base::FieldTrial::ActiveGroups active_groups;
|
| + base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
|
| + for (size_t i = 0; i < active_groups.size(); ++i) {
|
| + if (active_groups[i].trial_name == trial_name)
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + base::Lock lock_;
|
| + std::map<VariationKey, VariationParams> variation_params_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(VariationsParamAssociator);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +ActiveGroupId MakeActiveGroupId(const std::string& trial_name,
|
| + const std::string& group_name) {
|
| + ActiveGroupId id;
|
| + id.name = metrics::HashName(trial_name);
|
| + id.group = metrics::HashName(group_name);
|
| + return id;
|
| +}
|
| +
|
| +void AssociateGoogleVariationID(IDCollectionKey key,
|
| + const std::string& trial_name,
|
| + const std::string& group_name,
|
| + VariationID id) {
|
| + GroupMapAccessor::GetInstance()->AssociateID(
|
| + key, MakeActiveGroupId(trial_name, group_name), id, false);
|
| +}
|
| +
|
| +void AssociateGoogleVariationIDForce(IDCollectionKey key,
|
| + const std::string& trial_name,
|
| + const std::string& group_name,
|
| + VariationID id) {
|
| + GroupMapAccessor::GetInstance()->AssociateID(
|
| + key, MakeActiveGroupId(trial_name, group_name), id, true);
|
| +}
|
| +
|
| +VariationID GetGoogleVariationID(IDCollectionKey key,
|
| + const std::string& trial_name,
|
| + const std::string& group_name) {
|
| + return GroupMapAccessor::GetInstance()->GetID(
|
| + key, MakeActiveGroupId(trial_name, group_name));
|
| +}
|
| +
|
| +bool AssociateVariationParams(
|
| + const std::string& trial_name,
|
| + const std::string& group_name,
|
| + const std::map<std::string, std::string>& params) {
|
| + return VariationsParamAssociator::GetInstance()->AssociateVariationParams(
|
| + trial_name, group_name, params);
|
| +}
|
| +
|
| +bool GetVariationParams(const std::string& trial_name,
|
| + std::map<std::string, std::string>* params) {
|
| + return VariationsParamAssociator::GetInstance()->GetVariationParams(
|
| + trial_name, params);
|
| +}
|
| +
|
| +std::string GetVariationParamValue(const std::string& trial_name,
|
| + const std::string& param_name) {
|
| + std::map<std::string, std::string> params;
|
| + if (GetVariationParams(trial_name, ¶ms)) {
|
| + std::map<std::string, std::string>::iterator it = params.find(param_name);
|
| + if (it != params.end())
|
| + return it->second;
|
| + }
|
| + return std::string();
|
| +}
|
| +
|
| +// Functions below are exposed for testing explicitly behind this namespace.
|
| +// They simply wrap existing functions in this file.
|
| +namespace testing {
|
| +
|
| +void ClearAllVariationIDs() {
|
| + GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
|
| +}
|
| +
|
| +void ClearAllVariationParams() {
|
| + VariationsParamAssociator::GetInstance()->ClearAllParamsForTesting();
|
| +}
|
| +
|
| +} // namespace testing
|
| +
|
| +} // namespace chrome_variations
|
|
|