Index: net/cookies/cookie_monster.cc |
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc |
index 1d3814649ac9781444b8d54e0808a4cce547eef7..79a29bc9912b9d9f68b3884d6ebf20457fd37918 100644 |
--- a/net/cookies/cookie_monster.cc |
+++ b/net/cookies/cookie_monster.cc |
@@ -162,13 +162,10 @@ bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) { |
bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1, |
const CookieMonster::CookieMap::iterator& it2) { |
- // Cookies accessed less recently should be deleted first. |
if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) |
return it1->second->LastAccessDate() < it2->second->LastAccessDate(); |
- // In rare cases we might have two cookies with identical last access times. |
- // To preserve the stability of the sort, in these cases prefer to delete |
- // older cookies over newer ones. CreationDate() is guaranteed to be unique. |
+ // Ensure stability for == last access times by falling back to creation. |
return it1->second->CreationDate() < it2->second->CreationDate(); |
} |
@@ -250,30 +247,6 @@ void SplitCookieVectorIntoSecureAndNonSecure( |
} |
} |
-// Predicate to support PartitionCookieByPriority(). |
-struct CookiePriorityEqualsTo |
- : std::unary_function<const CookieMonster::CookieMap::iterator, bool> { |
- explicit CookiePriorityEqualsTo(CookiePriority priority) |
- : priority_(priority) {} |
- |
- bool operator()(const CookieMonster::CookieMap::iterator it) const { |
- return it->second->Priority() == priority_; |
- } |
- |
- const CookiePriority priority_; |
-}; |
- |
-// For a CookieItVector iterator range [|it_begin|, |it_end|), |
-// moves all cookies with a given |priority| to the beginning of the list. |
-// Returns: An iterator in [it_begin, it_end) to the first element with |
-// priority != |priority|, or |it_end| if all have priority == |priority|. |
-CookieMonster::CookieItVector::iterator PartitionCookieByPriority( |
- CookieMonster::CookieItVector::iterator it_begin, |
- CookieMonster::CookieItVector::iterator it_end, |
- CookiePriority priority) { |
- return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority)); |
-} |
- |
bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it, |
const Time& access_date) { |
return it->second->LastAccessDate() < access_date; |
@@ -1875,6 +1848,7 @@ size_t CookieMonster::GarbageCollect(const Time& current, |
num_deleted += |
GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its); |
+ // TODO(mkwst): Soften this. |
CookieItVector secure_cookie_its; |
if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) { |
VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies."; |
@@ -1889,56 +1863,26 @@ size_t CookieMonster::GarbageCollect(const Time& current, |
cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); |
DCHECK(purge_goal > kDomainPurgeCookies); |
- // Boundary iterators into |cookie_its| for different priorities. |
- CookieItVector::iterator it_bdd[4]; |
- // Intialize |it_bdd| while sorting |cookie_its| by priorities. |
- // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries. |
- it_bdd[0] = cookie_its->begin(); |
- it_bdd[3] = cookie_its->end(); |
- it_bdd[1] = |
- PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW); |
- it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3], |
- COOKIE_PRIORITY_MEDIUM); |
- size_t quota[3] = {kDomainCookiesQuotaLow, |
- kDomainCookiesQuotaMedium, |
- kDomainCookiesQuotaHigh}; |
- |
- // Purge domain cookies in 3 rounds. |
- // Round 1: consider low-priority cookies only: evict least-recently |
- // accessed, while protecting quota[0] of these from deletion. |
- // Round 2: consider {low, medium}-priority cookies, evict least-recently |
- // accessed, while protecting quota[0] + quota[1]. |
- // Round 3: consider all cookies, evict least-recently accessed. |
- size_t accumulated_quota = 0; |
- CookieItVector::iterator it_purge_begin = it_bdd[0]; |
- for (int i = 0; i < 3 && purge_goal > 0; ++i) { |
- accumulated_quota += quota[i]; |
- |
- size_t num_considered = it_bdd[i + 1] - it_purge_begin; |
- if (num_considered <= accumulated_quota) |
- continue; |
- |
- // Number of cookies that will be purged in this round. |
- size_t round_goal = |
- std::min(purge_goal, num_considered - accumulated_quota); |
- purge_goal -= round_goal; |
- |
- SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal); |
- // Cookies accessed on or after |safe_date| would have been safe from |
- // global purge, and we want to keep track of this. |
- CookieItVector::iterator it_purge_end = it_purge_begin + round_goal; |
- CookieItVector::iterator it_purge_middle = |
- LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date); |
- // Delete cookies accessed before |safe_date|. |
- num_deleted += GarbageCollectDeleteRange( |
- current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin, |
- it_purge_middle); |
- // Delete cookies accessed on or after |safe_date|. |
- num_deleted += GarbageCollectDeleteRange( |
- current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle, |
- it_purge_end); |
- it_purge_begin = it_purge_end; |
+ // Sort the cookies by access date, from least-recent to most-recent. |
+ std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter); |
+ |
+ // Remove all but the kDomainCookiesQuotaLow most-recently accessed |
+ // cookies with low-priority. Then, if we still need to remove cookies, |
+ // bump the quota and remove low- and medium-priority. Then, if we |
+ // _still_ need to remove cookies, bump the quota and remove cookies |
+ // with any priority. |
+ size_t quotas[3] = {kDomainCookiesQuotaLow, kDomainCookiesQuotaMedium, |
+ kDomainCookiesQuotaHigh}; |
+ size_t quota = 0; |
+ for (size_t i = 0; i < arraysize(quotas) && purge_goal; i++) { |
+ quota += quotas[i]; |
+ size_t just_deleted = |
+ PurgeLeastRecentMatches(cookie_its, static_cast<CookiePriority>(i), |
+ quota, purge_goal, safe_date); |
+ purge_goal -= just_deleted; |
+ num_deleted += just_deleted; |
} |
+ |
DCHECK_EQ(0U, purge_goal); |
} |
} |
@@ -1986,6 +1930,38 @@ size_t CookieMonster::GarbageCollect(const Time& current, |
return num_deleted; |
} |
+size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies, |
mmenke
2016/03/04 16:17:57
Do we still need the CookieItVector, or could we j
mmenke
2016/03/04 16:20:19
If we take enum that indicates the secure value we
Mike West
2016/03/04 16:34:23
We'd need to scope it to the key involved, but we
Mike West
2016/03/07 10:22:28
Looking at this again, if we use `cookies_` we'll
|
+ CookiePriority priority, |
+ size_t to_protect, |
+ size_t purge_goal, |
+ const base::Time& safe_date) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ size_t matches = std::count_if(cookies->begin(), cookies->end(), |
+ [priority](const CookieMap::iterator& it) { |
+ return it->second->Priority() <= priority; |
+ }); |
+ if (to_protect > matches) |
+ return 0; |
+ |
+ size_t to_remove = std::min(purge_goal, matches - to_protect); |
+ size_t removed = 0; |
+ for (auto it = cookies->begin(); |
+ it != cookies->end() && removed < to_remove;) { |
+ if ((*it)->second->Priority() <= priority) { |
+ InternalDeleteCookie(*it, true, |
+ (*it)->second->LastAccessDate() > safe_date |
+ ? DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE |
+ : DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE); |
Mike West
2016/03/04 16:34:23
Is anyone looking at these metrics? If not (and I'
mmenke
2016/03/04 16:47:44
You mean the deletion cause? We pass that on to t
Mike West
2016/03/07 10:22:28
I was more specifically referring to the distincti
mmenke
2016/03/07 17:46:03
Ah, right, didn't realize we're pushing a simpler
Mike West
2016/03/08 08:58:28
https://codereview.chromium.org/1769023003
|
+ it = cookies->erase(it); |
+ removed++; |
+ } else { |
+ it++; |
+ } |
+ } |
+ return removed; |
mmenke
2016/03/04 16:17:57
I think this entire method can be simpler:
for (a
Mike West
2016/03/04 16:34:23
We need to protect the X most-recently used cookie
mmenke
2016/03/04 16:40:51
Oh, right, I forgot about purge_goal...So we'd nee
Mike West
2016/03/04 16:46:28
Oh, that's clever. So we'd walk down to the |to_pr
mmenke
2016/03/04 16:48:29
Yes, that's exactly what I mean.
|
+} |
+ |
size_t CookieMonster::GarbageCollectExpired(const Time& current, |
const CookieMapItPair& itpair, |
CookieItVector* cookie_its) { |