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

Side by Side Diff: net/cookies/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: Cleanups; simplifying garbage collection; simplifying UMA; fixing off-by-1 meaning of max_size_. 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 "net/cookies/evicted_domain_cookie_counter.h"
6
7 #include <limits>
8 #include <queue>
9 #include <vector>
10
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/string_util.h"
14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
15 #include "net/cookies/canonical_cookie.h"
16
17 namespace net {
18
19 using base::Time;
20 using base::TimeDelta;
21
22 namespace {
23
24 const size_t kMaxEvictedDomainCookies = 500;
25 const size_t kPurgeEvictedDomainCookies = 100;
26
27 class DelegateImpl : public EvictedDomainCookieCounter::Delegate {
28 public:
29 DelegateImpl();
30
31 // EvictedDomainCookieCounter::Delegate implementation.
32 virtual void Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
33 const Time& reinstatement_time) OVERRIDE;
34 virtual Time CurrentTime() OVERRIDE;
35 };
36
37 DelegateImpl::DelegateImpl() {}
38
39 void DelegateImpl::Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
40 const Time& reinstatement_time) {
41 static TimeDelta time_min(TimeDelta::FromSeconds(1));
42 static TimeDelta time_max(TimeDelta::FromDays(7));
43 TimeDelta reinstatement_delay(reinstatement_time - ec.eviction_time_);
44 if (ec.is_google_) {
45 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesGoogleSeconds",
erikwright (departed) 2013/03/22 15:53:26 I believe that this macro already defines a static
erikwright (departed) 2013/03/22 15:53:26 Please check for other uses of HISTOGRAM_CUSTOM_TI
huangs 2013/03/22 21:38:07 Yeah it can be inlined.
huangs 2013/03/22 21:38:07 I was probably looking at the wrong things. Remov
46 reinstatement_delay, time_min, time_max, 50);
47 } else {
48 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesOtherSeconds",
49 reinstatement_delay, time_min, time_max, 50);
50 }
51 }
52
53 Time DelegateImpl::CurrentTime() {
54 return Time::Now();
55 }
56
57 } // namespace
58
59 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
60 scoped_refptr<CookieMonster::Delegate> next_delegate)
61 : next_delegate_(next_delegate),
62 reporter_(new DelegateImpl),
63 max_size_(kMaxEvictedDomainCookies),
64 purge_count_(kPurgeEvictedDomainCookies) {
65 DCHECK(reporter_);
erikwright (departed) 2013/03/22 15:53:26 Not required here, since you just assigned it thre
huangs 2013/03/22 21:38:07 Done.
66 }
67
68 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
69 scoped_refptr<CookieMonster::Delegate> next_delegate,
70 scoped_ptr<Delegate> reporter,
71 size_t max_size,
72 size_t purge_count)
73 : next_delegate_(next_delegate),
74 reporter_(reporter.Pass()),
75 max_size_(max_size),
76 purge_count_(purge_count) {
77 DCHECK(reporter_);
78 DCHECK(purge_count < max_size_);
erikwright (departed) 2013/03/22 15:53:26 Unless something is going to crash later because o
huangs 2013/03/22 21:38:07 These are both size_t's, and a difference will be
79 }
80
81 EvictedDomainCookieCounter::~EvictedDomainCookieCounter() {
82 STLDeleteContainerPairSecondPointers(evicted_cookies_.begin(),
83 evicted_cookies_.end());
84 }
85
86 // static
87 // Simplified from google_util.cc: IsGoogleHostname().
88 bool EvictedDomainCookieCounter::UnsafeIsGoogleCookie(
89 const CanonicalCookie& cc) {
90 const std::string& host(cc.Domain());
91 size_t tld_length =
92 RegistryControlledDomainService::GetRegistryLength(host, false);
93 if ((tld_length == 0) || (tld_length == std::string::npos))
94 return false;
95
96 std::string host_minus_tld(host, 0, host.length() - tld_length);
97 return LowerCaseEqualsASCII(host_minus_tld, "google.") ||
98 EndsWith(host_minus_tld, ".google.", false);
99 }
100
101 size_t EvictedDomainCookieCounter::GetStorageSize() const {
102 return evicted_cookies_.size();
103 }
104
105 void EvictedDomainCookieCounter::OnCookieChanged(const CanonicalCookie& cc,
106 bool removed,
107 ChangeCause cause) {
108 EvictedDomainCookieCounter::EvictedCookieKey key(GetKey(cc));
109 Time current(reporter_->CurrentTime());
110 if (removed) {
111 if (cause == CookieMonster::Delegate::CHANGE_COOKIE_EVICTED)
112 StoreEvictedCookie(key, cc, current);
113 else // Explicit deletion, so stop tracking.
114 FreeEvictedCookie(key);
115 } else { // Including adds or updates.
116 if (ProcessCookieReinstatement(key, cc, current))
erikwright (departed) 2013/03/22 15:53:26 I think it would be clearer if ProcessCookieReinst
huangs 2013/03/22 21:38:07 Renamed, and moved deletion to the routine.
117 FreeEvictedCookie(key);
118 }
119
120 if (next_delegate_)
121 next_delegate_->OnCookieChanged(cc, removed, cause);
122 }
123
124 // static
125 EvictedDomainCookieCounter::EvictedCookieKey
126 EvictedDomainCookieCounter::GetKey(const CanonicalCookie& cc) {
127 return cc.Domain() + ";" + cc.Path() + ";" + cc.Name();
128 }
129
130 void EvictedDomainCookieCounter::FreeEvictedCookie(
131 const EvictedCookieKey& key) {
132 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
133 if (it != evicted_cookies_.end()) {
134 delete it->second;
135 evicted_cookies_.erase(it);
136 }
137 }
138
139 // |current| is passed by value, in case it came from a to-be-deleted element.
140 void EvictedDomainCookieCounter::FreeExpiredEvictedCookies(Time current) {
141 EvictedCookieMap::iterator it = evicted_cookies_.begin();
142 while (it != evicted_cookies_.end()) {
143 if (it->second->is_expired(current)) {
144 delete it->second;
145 evicted_cookies_.erase(it++); // Post-increment idiom.
146 } else {
147 ++it;
148 }
149 }
150 }
151
152 void EvictedDomainCookieCounter::GarbageCollect(const Time& current) {
153 if (evicted_cookies_.size() <= max_size_)
154 return;
155
156 // From |evicted_cookies_|, removed all expired cookies, and remove cookies
157 // with the oldest |eviction_time_| until |size_goal| is attained.
158 size_t size_goal = max_size_ - purge_count_;
159 // Bound on number of non-expired cookies to remove.
160 size_t remove_quota = evicted_cookies_.size() - size_goal;
161 DCHECK(remove_quota > 0);
162
163 // Among evicted cookies with the same eviction time, bias may arise owing to
erikwright (departed) 2013/03/22 15:53:26 LOL. You seem to take this personally. This does n
huangs 2013/03/22 21:38:07 Removed. :(
164 // traversal order in EvictedCookieMap. However, we deem this effect minor,
165 // so we won't resolve ties.
166 struct EvictedCookiePriorityQueueEntry {
erikwright (departed) 2013/03/22 15:53:26 IIUC, you don't need a custom type here anymore, j
huangs 2013/03/22 21:38:07 The second type parameter to std::priority_queue i
167 EvictedCookie* cookie_ptr;
168
169 EvictedCookiePriorityQueueEntry(EvictedCookie* cookie_ptr)
170 : cookie_ptr(cookie_ptr) {}
171
172 bool operator < (const EvictedCookiePriorityQueueEntry& other) const {
173 return cookie_ptr->eviction_time_ < other.cookie_ptr->eviction_time_;
174 }
175 };
176
177 // Use priority queue to store oldest cookies, resize as necessary.
178 std::priority_queue<EvictedCookiePriorityQueueEntry> oldest_set;
179 for (EvictedCookieMap::iterator it = evicted_cookies_.begin();
180 it != evicted_cookies_.end(); ++it) {
181 if (it->second->is_expired(current)) // Will be removed, so decrease quota.
182 remove_quota = remove_quota ? remove_quota - 1 : 0; // Cap to 0 (size_t).
183 else
184 oldest_set.push(EvictedCookiePriorityQueueEntry(it->second));
185
186 if (oldest_set.size() > remove_quota)
187 oldest_set.pop(); // Spare the youngest element from deletion.
188 }
189 DCHECK(oldest_set.size() <= remove_quota);
190
191 // Mark oldest non-expired cookies as expired, for removal.
192 while (!oldest_set.empty()) {
193 oldest_set.top().cookie_ptr->set_expired();
194 oldest_set.pop();
195 }
196
197 FreeExpiredEvictedCookies(current);
198 // Apply stricter check if non-expired cookies were deleted.
199 DCHECK(remove_quota ? evicted_cookies_.size() == size_goal :
200 evicted_cookies_.size() <= size_goal);
201 }
202
203 void EvictedDomainCookieCounter::StoreEvictedCookie(const EvictedCookieKey& key,
204 const CanonicalCookie& cc,
205 const Time& current) {
206 if (!cc.IsExpired(current)) {
207 FreeEvictedCookie(key); // Deallocate explicitly.
208
209 EvictedCookie* ec =
210 new EvictedCookie(current, cc.ExpiryDate(), UnsafeIsGoogleCookie(cc));
211 evicted_cookies_.insert(EvictedCookieMap::value_type(key, ec));
212
213 GarbageCollect(current);
214 }
215 }
216
217 bool EvictedDomainCookieCounter::ProcessCookieReinstatement(
218 const EvictedCookieKey& key,
219 const CanonicalCookie& cc,
220 const Time& current) {
221 bool ret = false;
222 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
huangs 2013/03/22 21:38:07 If cc is expired, we would count it as being reins
223 if (it != evicted_cookies_.end()) {
224 if (!it->second->is_expired(current))
225 reporter_->Report(*it->second, current);
226 ret = true;
227 }
228 return ret;
229 }
230
231 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698