1 // Copyright 2014 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/caching_permuted_entropy_provider.h"
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/pref_service.h"
13 #include "components/variations/pref_names.h"
17 CachingPermutedEntropyProvider::CachingPermutedEntropyProvider(
18 PrefService
* local_state
,
19 uint16 low_entropy_source
,
20 size_t low_entropy_source_max
)
21 : PermutedEntropyProvider(low_entropy_source
, low_entropy_source_max
),
22 local_state_(local_state
) {
26 CachingPermutedEntropyProvider::~CachingPermutedEntropyProvider() {
30 void CachingPermutedEntropyProvider::RegisterPrefs(
31 PrefRegistrySimple
* registry
) {
32 registry
->RegisterStringPref(prefs::kVariationsPermutedEntropyCache
,
37 void CachingPermutedEntropyProvider::ClearCache(PrefService
* local_state
) {
38 local_state
->ClearPref(prefs::kVariationsPermutedEntropyCache
);
41 uint16
CachingPermutedEntropyProvider::GetPermutedValue(
42 uint32 randomization_seed
) const {
43 DCHECK(thread_checker_
.CalledOnValidThread());
46 if (!FindValue(randomization_seed
, &value
)) {
47 value
= PermutedEntropyProvider::GetPermutedValue(randomization_seed
);
48 AddToCache(randomization_seed
, value
);
53 void CachingPermutedEntropyProvider::ReadFromLocalState() const {
54 const std::string base64_cache_data
=
55 local_state_
->GetString(prefs::kVariationsPermutedEntropyCache
);
56 std::string cache_data
;
57 if (!base::Base64Decode(base64_cache_data
, &cache_data
) ||
58 !cache_
.ParseFromString(cache_data
)) {
59 local_state_
->ClearPref(prefs::kVariationsPermutedEntropyCache
);
64 void CachingPermutedEntropyProvider::UpdateLocalState() const {
65 std::string serialized
;
66 cache_
.SerializeToString(&serialized
);
68 std::string base64_encoded
;
69 base::Base64Encode(serialized
, &base64_encoded
);
70 local_state_
->SetString(prefs::kVariationsPermutedEntropyCache
,
74 void CachingPermutedEntropyProvider::AddToCache(uint32 randomization_seed
,
76 PermutedEntropyCache::Entry
* entry
;
77 const int kMaxSize
= 25;
78 if (cache_
.entry_size() >= kMaxSize
) {
79 // If the cache is full, evict the first entry, swapping later entries in
80 // to take its place. This effectively creates a FIFO cache, which is good
81 // enough here because the expectation is that there shouldn't be more than
82 // |kMaxSize| field trials at any given time, so eviction should happen very
83 // rarely, only as new trials are introduced, evicting old expired trials.
84 for (int i
= 1; i
< kMaxSize
; ++i
)
85 cache_
.mutable_entry()->SwapElements(i
- 1, i
);
86 entry
= cache_
.mutable_entry(kMaxSize
- 1);
88 entry
= cache_
.add_entry();
91 entry
->set_randomization_seed(randomization_seed
);
92 entry
->set_value(value
);
97 bool CachingPermutedEntropyProvider::FindValue(uint32 randomization_seed
,
98 uint16
* value
) const {
99 for (int i
= 0; i
< cache_
.entry_size(); ++i
) {
100 if (cache_
.entry(i
).randomization_seed() == randomization_seed
) {
101 *value
= cache_
.entry(i
).value();
108 } // namespace metrics