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

Side by Side Diff: net/base/cookie_monster.cc

Issue 99100: Update cookie expiry policy to attempt to avoid deleting "in-use" cookies. S... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 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
« no previous file with comments | « net/base/cookie_monster.h ('k') | net/base/cookie_monster_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Portions of this code based on Mozilla: 5 // Portions of this code based on Mozilla:
6 // (netwerk/cookie/src/nsCookieService.cpp) 6 // (netwerk/cookie/src/nsCookieService.cpp)
7 /* ***** BEGIN LICENSE BLOCK ***** 7 /* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 * 9 *
10 * The contents of this file are subject to the Mozilla Public License Version 10 * The contents of this file are subject to the Mozilla Public License Version
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 1) 61 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 1)
62 #else 62 #else
63 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 0) 63 #define COOKIE_DLOG(severity) DLOG_IF(INFO, 0)
64 #endif 64 #endif
65 65
66 using base::Time; 66 using base::Time;
67 using base::TimeDelta; 67 using base::TimeDelta;
68 68
69 namespace net { 69 namespace net {
70 70
71
71 // Cookie garbage collection thresholds. Based off of the Mozilla defaults. 72 // Cookie garbage collection thresholds. Based off of the Mozilla defaults.
72 // It might seem scary to have a high purge value, but really it's not. You 73 static const size_t kMaxCookiesPerHost = 50;
73 // just make sure that you increase the max to cover the increase in purge, 74 static const size_t kMaxCookiesTotal = 2000;
74 // and we would have been purging the same amount of cookies. We're just 75 static const int kMaxCookieAgeSeconds = 30 * 24 * 60 * 60; // 30 days
75 // going through the garbage collection process less often. 76 static const double kPurgeOverageFactor = 1.1;
76 static const size_t kNumCookiesPerHost = 70; // ~50 cookies
77 static const size_t kNumCookiesPerHostPurge = 20;
78 static const size_t kNumCookiesTotal = 3300; // ~3000 cookies
79 static const size_t kNumCookiesTotalPurge = 300;
80 77
81 // Default minimum delay after updating a cookie's LastAccessDate before we 78 // Default minimum delay after updating a cookie's LastAccessDate before we
82 // will update it again. 79 // will update it again.
83 static const int kDefaultAccessUpdateThresholdSeconds = 60; 80 static const int kDefaultAccessUpdateThresholdSeconds = 60;
84 81
85 // static 82 // static
86 bool CookieMonster::enable_file_scheme_ = false; 83 bool CookieMonster::enable_file_scheme_ = false;
87 84
88 // static 85 // static
89 void CookieMonster::EnableFileScheme() { 86 void CookieMonster::EnableFileScheme() {
(...skipping 21 matching lines...) Expand all
111 } 108 }
112 109
113 void CookieMonster::InitStore() { 110 void CookieMonster::InitStore() {
114 DCHECK(store_) << "Store must exist to initialize"; 111 DCHECK(store_) << "Store must exist to initialize";
115 112
116 // Initialize the store and sync in any saved persistent cookies. We don't 113 // Initialize the store and sync in any saved persistent cookies. We don't
117 // care if it's expired, insert it so it can be garbage collected, removed, 114 // care if it's expired, insert it so it can be garbage collected, removed,
118 // and sync'd. 115 // and sync'd.
119 std::vector<KeyedCanonicalCookie> cookies; 116 std::vector<KeyedCanonicalCookie> cookies;
120 // Reserve space for the maximum amount of cookies a database should have. 117 // Reserve space for the maximum amount of cookies a database should have.
121 // This prevents multiple vector growth / copies as we append cookies. 118 // This prevents multiple vector growth / copies as we append cookies. Note
122 cookies.reserve(kNumCookiesTotal); 119 // that if we have too many recent cookies, we'll still cross this limit;
123 store_->Load(&cookies); 120 // however, since std::vector<> grows by 50% when inserting a new element
121 // into a full vector, we should have few of these additional resizes.
122 cookies.reserve(static_cast<int>(kMaxCookiesTotal * kPurgeOverageFactor));
123 store_->Load(&cookies, &least_recent_access_);
124 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin(); 124 for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin();
125 it != cookies.end(); ++it) { 125 it != cookies.end(); ++it) {
126 InternalInsertCookie(it->first, it->second, false); 126 InternalInsertCookie(it->first, it->second, false);
127 } 127 }
128 } 128 }
129 129
130 void CookieMonster::SetDefaultCookieableSchemes() { 130 void CookieMonster::SetDefaultCookieableSchemes() {
131 // Note: file must be the last scheme. 131 // Note: file must be the last scheme.
132 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" }; 132 static const char* kDefaultCookieableSchemes[] = { "http", "https", "file" };
133 int num_schemes = enable_file_scheme_ ? 3 : 2; 133 int num_schemes = enable_file_scheme_ ? 3 : 2;
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 iter != cookies.end(); ++iter) 509 iter != cookies.end(); ++iter)
510 SetCookieWithOptions(url, *iter, options); 510 SetCookieWithOptions(url, *iter, options);
511 } 511 }
512 512
513 void CookieMonster::InternalInsertCookie(const std::string& key, 513 void CookieMonster::InternalInsertCookie(const std::string& key,
514 CanonicalCookie* cc, 514 CanonicalCookie* cc,
515 bool sync_to_store) { 515 bool sync_to_store) {
516 if (cc->IsPersistent() && store_ && sync_to_store) 516 if (cc->IsPersistent() && store_ && sync_to_store)
517 store_->AddCookie(key, *cc); 517 store_->AddCookie(key, *cc);
518 cookies_.insert(CookieMap::value_type(key, cc)); 518 cookies_.insert(CookieMap::value_type(key, cc));
519 const Time last_access = cc->LastAccessDate();
520 if (least_recent_access_.is_null() || (last_access < least_recent_access_))
521 least_recent_access_ = last_access;
519 } 522 }
520 523
521 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc) { 524 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc) {
522 // Based off the Mozilla code. When a cookie has been accessed recently, 525 // Based off the Mozilla code. When a cookie has been accessed recently,
523 // don't bother updating its access time again. This reduces the number of 526 // don't bother updating its access time again. This reduces the number of
524 // updates we do during pageload, which in turn reduces the chance our storage 527 // updates we do during pageload, which in turn reduces the chance our storage
525 // backend will hit its batch thresholds and be forced to update. 528 // backend will hit its batch thresholds and be forced to update.
526 const Time current = Time::Now(); 529 const Time current = Time::Now();
527 if ((current - cc->LastAccessDate()) < last_access_threshold_) 530 if ((current - cc->LastAccessDate()) < last_access_threshold_)
528 return; 531 return;
529 532
530 cc->SetLastAccessDate(current); 533 cc->SetLastAccessDate(current);
531 if (cc->IsPersistent() && store_) 534 if (cc->IsPersistent() && store_)
532 store_->UpdateCookieAccessTime(*cc); 535 store_->UpdateCookieAccessTime(*cc);
536 if (least_recent_access_.is_null() || (current < least_recent_access_))
537 least_recent_access_ = current;
533 } 538 }
534 539
535 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, 540 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
536 bool sync_to_store) { 541 bool sync_to_store) {
537 CanonicalCookie* cc = it->second; 542 CanonicalCookie* cc = it->second;
538 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString(); 543 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString();
539 if (cc->IsPersistent() && store_ && sync_to_store) 544 if (cc->IsPersistent() && store_ && sync_to_store)
540 store_->DeleteCookie(*cc); 545 store_->DeleteCookie(*cc);
541 cookies_.erase(it); 546 cookies_.erase(it);
542 delete cc; 547 delete cc;
(...skipping 29 matching lines...) Expand all
572 } 577 }
573 } 578 }
574 return skipped_httponly; 579 return skipped_httponly;
575 } 580 }
576 581
577 int CookieMonster::GarbageCollect(const Time& current, 582 int CookieMonster::GarbageCollect(const Time& current,
578 const std::string& key) { 583 const std::string& key) {
579 int num_deleted = 0; 584 int num_deleted = 0;
580 585
581 // Collect garbage for this key. 586 // Collect garbage for this key.
582 if (cookies_.count(key) > kNumCookiesPerHost) { 587 if (cookies_.count(key) >= (kMaxCookiesPerHost * kPurgeOverageFactor)) {
583 COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key; 588 COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key;
584 num_deleted += GarbageCollectRange(current, cookies_.equal_range(key), 589 num_deleted += GarbageCollectRange(current, cookies_.equal_range(key),
585 kNumCookiesPerHost, kNumCookiesPerHostPurge); 590 kMaxCookiesPerHost, TimeDelta());
586 } 591 }
587 592
588 // Collect garbage for everything. 593 // Collect garbage for everything.
589 if (cookies_.size() > kNumCookiesTotal) { 594 if ((cookies_.size() >= (kMaxCookiesTotal * kPurgeOverageFactor)) &&
595 (least_recent_access_.is_null() ||
596 ((current - least_recent_access_) >=
597 TimeDelta::FromSeconds(static_cast<int>(kMaxCookieAgeSeconds *
598 kPurgeOverageFactor))))) {
590 COOKIE_DLOG(INFO) << "GarbageCollect() everything"; 599 COOKIE_DLOG(INFO) << "GarbageCollect() everything";
591 num_deleted += GarbageCollectRange(current, 600 num_deleted += GarbageCollectRange(current,
592 CookieMapItPair(cookies_.begin(), cookies_.end()), kNumCookiesTotal, 601 CookieMapItPair(cookies_.begin(), cookies_.end()), kMaxCookiesTotal,
593 kNumCookiesTotalPurge); 602 TimeDelta::FromSeconds(kMaxCookieAgeSeconds));
594 } 603 }
595 604
596 return num_deleted; 605 return num_deleted;
597 } 606 }
598 607
599 static bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, 608 static bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1,
600 const CookieMonster::CookieMap::iterator& it2) { 609 const CookieMonster::CookieMap::iterator& it2) {
601 // Cookies accessed less recently should be deleted first. 610 // Cookies accessed less recently should be deleted first.
602 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) 611 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
603 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); 612 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
604 613
605 // In rare cases we might have two cookies with identical last access times. 614 // In rare cases we might have two cookies with identical last access times.
606 // To preserve the stability of the sort, in these cases prefer to delete 615 // To preserve the stability of the sort, in these cases prefer to delete
607 // older cookies over newer ones. CreationDate() is guaranteed to be unique. 616 // older cookies over newer ones. CreationDate() is guaranteed to be unique.
608 return it1->second->CreationDate() < it2->second->CreationDate(); 617 return it1->second->CreationDate() < it2->second->CreationDate();
609 } 618 }
610 619
611 int CookieMonster::GarbageCollectRange(const Time& current, 620 int CookieMonster::GarbageCollectRange(const Time& current,
612 const CookieMapItPair& itpair, 621 const CookieMapItPair& itpair,
613 size_t num_max, 622 size_t max_cookies,
614 size_t num_purge) { 623 const TimeDelta& purge_age) {
615 // First, delete anything that's expired. 624 // First, delete anything that's expired.
616 std::vector<CookieMap::iterator> cookie_its; 625 std::vector<CookieMap::iterator> cookie_its;
617 int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its); 626 int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its);
618 627
619 // If the range still has too many cookies, delete the least recently used. 628 // If the range still has too many cookies, delete the least recently used.
620 if (cookie_its.size() > num_max) { 629 if (cookie_its.size() > max_cookies) {
621 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; 630 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect.";
622 // Purge down to (|num_max| - |num_purge|) total cookies. 631 // Purge down to |max_cookies| total cookies.
623 DCHECK(num_purge <= num_max); 632 size_t num_purge = cookie_its.size() - max_cookies;
624 num_purge += cookie_its.size() - num_max;
625 633
626 std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge, 634 std::partial_sort(cookie_its.begin(),
627 cookie_its.end(), LRUCookieSorter); 635 cookie_its.begin() + std::min(cookie_its.size(), num_purge + 1),
628 for (size_t i = 0; i < num_purge; ++i) 636 cookie_its.end(), LRUCookieSorter);
637 const bool only_purge_old_cookies = (purge_age != TimeDelta());
638 for (size_t i = 0; i < num_purge;) {
639 // Stop purging once we've run out of cookies that are "old enough".
640 if (only_purge_old_cookies &&
641 ((current - cookie_its[i]->second->LastAccessDate()) < purge_age))
642 return num_deleted + i;
643
629 InternalDeleteCookie(cookie_its[i], true); 644 InternalDeleteCookie(cookie_its[i], true);
630 645
646 // Update least_recent_access_ now that we've deleted the LRU cookie.
647 ++i;
648 if (i < cookie_its.size())
649 least_recent_access_ = cookie_its[i]->second->LastAccessDate();
650 }
651
631 num_deleted += num_purge; 652 num_deleted += num_purge;
632 } 653 }
633 654
634 return num_deleted; 655 return num_deleted;
635 } 656 }
636 657
637 int CookieMonster::GarbageCollectExpired( 658 int CookieMonster::GarbageCollectExpired(
638 const Time& current, 659 const Time& current,
639 const CookieMapItPair& itpair, 660 const CookieMapItPair& itpair,
640 std::vector<CookieMap::iterator>* cookie_its) { 661 std::vector<CookieMap::iterator>* cookie_its) {
(...skipping 18 matching lines...) Expand all
659 InitIfNecessary(); 680 InitIfNecessary();
660 681
661 int num_deleted = 0; 682 int num_deleted = 0;
662 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { 683 for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
663 CookieMap::iterator curit = it; 684 CookieMap::iterator curit = it;
664 ++it; 685 ++it;
665 InternalDeleteCookie(curit, sync_to_store); 686 InternalDeleteCookie(curit, sync_to_store);
666 ++num_deleted; 687 ++num_deleted;
667 } 688 }
668 689
690 least_recent_access_ = Time();
691
669 return num_deleted; 692 return num_deleted;
670 } 693 }
671 694
672 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin, 695 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
673 const Time& delete_end, 696 const Time& delete_end,
674 bool sync_to_store) { 697 bool sync_to_store) {
675 AutoLock autolock(lock_); 698 AutoLock autolock(lock_);
676 InitIfNecessary(); 699 InitIfNecessary();
677 700
678 int num_deleted = 0; 701 int num_deleted = 0;
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
1124 return true; 1147 return true;
1125 } 1148 }
1126 1149
1127 std::string CookieMonster::CanonicalCookie::DebugString() const { 1150 std::string CookieMonster::CanonicalCookie::DebugString() const {
1128 return StringPrintf("name: %s value: %s path: %s creation: %llu", 1151 return StringPrintf("name: %s value: %s path: %s creation: %llu",
1129 name_.c_str(), value_.c_str(), path_.c_str(), 1152 name_.c_str(), value_.c_str(), path_.c_str(),
1130 creation_date_.ToTimeT()); 1153 creation_date_.ToTimeT());
1131 } 1154 }
1132 1155
1133 } // namespace 1156 } // namespace
OLDNEW
« no previous file with comments | « net/base/cookie_monster.h ('k') | net/base/cookie_monster_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698