Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(410)

Side by Side Diff: chrome/browser/net/evicted_domain_cookie_counter.cc

Issue 12805010: Implementing EvictedDomainCookieCounter to keep user metrics on cookie eviction and reinstatement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moving EvictedDomainCookieCounter to chrome/browser/net; fixing GarbageCollect() algorithm. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/net/evicted_domain_cookie_counter.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/google/google_util.h"
14 #include "net/cookies/canonical_cookie.h"
15
16 namespace chrome_browser_net {
17
18 using base::Time;
19 using base::TimeDelta;
20
21 namespace {
22
23 const size_t kMaxEvictedDomainCookies = 500;
24 const size_t kPurgeEvictedDomainCookies = 100;
25
26 class DelegateImpl : public EvictedDomainCookieCounter::Delegate {
27 public:
28 DelegateImpl();
29
30 // EvictedDomainCookieCounter::Delegate implementation.
31 virtual void Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
32 const Time& reinstatement_time) OVERRIDE;
33 virtual Time CurrentTime() OVERRIDE;
34 };
35
36 DelegateImpl::DelegateImpl() {}
37
38 void DelegateImpl::Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
39 const Time& reinstatement_time) {
40 TimeDelta reinstatement_delay(reinstatement_time - ec.eviction_time_);
41 // Need to duplicate HISTOGRAM_CUSTOM_TIMES(), since it is a macro that
42 // defines a static variable.
43 if (ec.is_google_) {
44 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesGoogle",
45 reinstatement_delay,
46 TimeDelta::FromSeconds(1),
47 TimeDelta::FromDays(7),
48 50);
49 } else {
50 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesOther",
51 reinstatement_delay,
52 TimeDelta::FromSeconds(1),
53 TimeDelta::FromDays(7),
54 50);
55 }
56 }
57
58 Time DelegateImpl::CurrentTime() {
59 return Time::Now();
60 }
61
62 // Computes a key for |cc| compatible with CanonicalCookie::IsEquivalent(),
63 // i.e., IsEquivalent(a, b) ==> GetKey(a) == GetKey(b).
64 EvictedDomainCookieCounter::EvictedCookieKey GetKey(
erikwright (departed) 2013/03/27 01:33:44 Hmm, OK, I guess private static for this is better
huangs 2013/03/28 22:56:21 Done; moved back to private static, made typedef p
65 const net::CanonicalCookie& cc) {
66 return cc.Domain() + ";" + cc.Path() + ";" + cc.Name();
67 }
68
69 } // namespace
70
71 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
72 scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate)
73 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
74 delegate_(new DelegateImpl),
75 max_size_(kMaxEvictedDomainCookies),
76 purge_count_(kPurgeEvictedDomainCookies) {
77 }
78
79 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
80 scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate,
81 scoped_ptr<Delegate> delegate,
82 size_t max_size,
83 size_t purge_count)
84 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
85 delegate_(delegate.Pass()),
86 max_size_(max_size),
87 purge_count_(purge_count) {
88 DCHECK(delegate_);
89 DCHECK(purge_count < max_size_);
90 }
91
92 EvictedDomainCookieCounter::~EvictedDomainCookieCounter() {
93 STLDeleteContainerPairSecondPointers(evicted_cookies_.begin(),
94 evicted_cookies_.end());
95 }
96
97 size_t EvictedDomainCookieCounter::GetStorageSize() const {
98 return evicted_cookies_.size();
99 }
100
101 void EvictedDomainCookieCounter::OnCookieChanged(const net::CanonicalCookie& cc,
102 bool removed,
103 ChangeCause cause) {
104 EvictedDomainCookieCounter::EvictedCookieKey key(GetKey(cc));
105 Time current(delegate_->CurrentTime());
106 if (removed) {
107 if (cause == net::CookieMonster::Delegate::CHANGE_COOKIE_EVICTED)
108 StoreEvictedCookie(key, cc, current);
109 } else { // Includes adds or updates.
110 ProcessNewCookie(key, cc, current);
111 }
112
113 if (next_cookie_monster_delegate_)
114 next_cookie_monster_delegate_->OnCookieChanged(cc, removed, cause);
115 }
116
117 void EvictedDomainCookieCounter::GarbageCollect(const Time& current) {
118 if (evicted_cookies_.size() <= max_size_)
119 return;
120
121 // From |evicted_cookies_|, removed all expired cookies, and remove cookies
122 // with the oldest |eviction_time_| so that |size_goal| is attained.
123 size_t size_goal = max_size_ - purge_count_;
124 // Bound on number of non-expired cookies to remove.
125 size_t remove_quota = evicted_cookies_.size() - size_goal;
126 DCHECK(remove_quota > 0);
127
128 std::vector<EvictedCookieMap::iterator> remove_list;
129 remove_list.reserve(evicted_cookies_.size());
130
131 EvictedCookieMap::iterator it = evicted_cookies_.begin();
132 while (it != evicted_cookies_.end()) {
133 if (it->second->is_expired(current)) {
134 delete it->second;
135 evicted_cookies_.erase(it++); // Post-increment idiom for in-loop removal.
136 remove_quota -= !!remove_quota; // Decrease until 0 is reached.
erikwright (departed) 2013/03/27 01:33:44 This is exceptionally clever but decreases readabi
huangs 2013/03/28 22:56:21 Done.
137 } else {
138 if (remove_quota) // Don't bother storing if quota met.
139 remove_list.push_back(it);
140 ++it;
141 }
142 }
143
144 // Comparator for sorting, to make recently evicted cookies appear earlier.
145 struct {
146 bool operator() (const EvictedCookieMap::iterator ec1,
147 const EvictedCookieMap::iterator ec2) {
148 return ec1->second->eviction_time_ < ec2->second->eviction_time_;
149 }
150 } comparator;
151
152 // Free the oldest |remove_quota| non-expired cookies.
153 std::partial_sort(remove_list.begin(), remove_list.begin() + remove_quota,
154 remove_list.end(), comparator);
155 for (size_t i = 0; i < remove_quota; ++i) {
156 delete remove_list[i]->second;
157 evicted_cookies_.erase(remove_list[i]);
158 }
159
160 // Apply stricter check if non-expired cookies were deleted.
161 DCHECK(remove_quota ? evicted_cookies_.size() == size_goal :
162 evicted_cookies_.size() <= size_goal);
163 }
164
165 void EvictedDomainCookieCounter::StoreEvictedCookie(
166 const EvictedCookieKey& key,
167 const net::CanonicalCookie& cc,
168 const Time& current) {
169 bool is_google = google_util::IsGoogleHostname(
170 cc.Domain(), google_util::ALLOW_SUBDOMAIN);
171 EvictedCookie* ec = new EvictedCookie(current, cc.ExpiryDate(), is_google);
172 std::pair<EvictedCookieMap::iterator, bool> prev_entry =
173 evicted_cookies_.insert(EvictedCookieMap::value_type(key, ec));
174 if (!prev_entry.second) {
175 NOTREACHED();
176 delete prev_entry.first->second;
erikwright (departed) 2013/03/27 01:33:44 and, I suppose: prev_entry.first->second = ec
huangs 2013/03/28 22:56:21 That was a genuine mistake; I thought that insert
177 }
178
179 GarbageCollect(current);
180 }
181
182 void EvictedDomainCookieCounter::ProcessNewCookie(
183 const EvictedCookieKey& key,
184 const net::CanonicalCookie& cc,
185 const Time& current) {
186 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
187 if (it != evicted_cookies_.end()) {
188 if (!it->second->is_expired(current))
189 delegate_->Report(*it->second, current); // Reinstatement.
190 delete it->second;
191 evicted_cookies_.erase(it);
192 }
193 }
194
195 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/evicted_domain_cookie_counter.h ('k') | chrome/browser/net/evicted_domain_cookie_counter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698