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

Unified Diff: net/base/cookie_monster.cc

Issue 7864008: Split initial load of cookies by domains (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: net/base/cookie_monster.cc
===================================================================
--- net/base/cookie_monster.cc (revision 103757)
+++ net/base/cookie_monster.cc (working copy)
@@ -49,6 +49,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -67,6 +68,25 @@
using base::TimeDelta;
using base::TimeTicks;
+// In steady state, most cookie requests can be satisfied by the in memory
+// cookie monster store. However, if a request comes in during the initial
+// cookie load, it must be delayed until that load completes. That is done by
+// queueing it on CookieMonster::queue_ and running it when notification of
+// cookie load completion is received via CookieMonster::OnLoaded. This callback
+// is passed to the persistent store from CookieMonster::InitStore(), which is
+// called on the first operation invoked on the CookieMonster.)
+//
+// On the browser critical paths (e.g. for loading initial web pages in a
+// session restore) it may take too long to wait for the full load. In this case
+// a priority load is triggered by calling PersistentCookieStore::
+// LoadCookiesForKey. The request is queued in CookieMonster::tasks_queued
+// and executed upon receiving notification of key load completion via
+// CookieMonster::OnKeyLoaded(). If multiple requests for the same eTLD+1 are
+// received before key load completion, only the first request calls
+// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
+// in CookieMonster::tasks_queued and executed upon receiving notification of
+// key load completion triggered by the first request for the same eTLD+1.
+
static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
namespace net {
@@ -993,7 +1013,7 @@
expiration_time, secure, http_only,
callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) {
@@ -1011,7 +1031,7 @@
scoped_refptr<GetAllCookiesForURLWithOptionsTask> task =
new GetAllCookiesForURLWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetAllCookiesForURLAsync(
@@ -1021,7 +1041,7 @@
scoped_refptr<GetAllCookiesForURLWithOptionsTask> task =
new GetAllCookiesForURLWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteAllAsync(const DeleteCallback& callback) {
@@ -1046,7 +1066,7 @@
scoped_refptr<DeleteAllForHostTask> task =
new DeleteAllForHostTask(this, url, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteCanonicalCookieAsync(
@@ -1066,7 +1086,7 @@
scoped_refptr<SetCookieWithOptionsTask> task =
new SetCookieWithOptionsTask(this, url, cookie_line, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetCookiesWithOptionsAsync(
@@ -1076,7 +1096,7 @@
scoped_refptr<GetCookiesWithOptionsTask> task =
new GetCookiesWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetCookiesWithInfoAsync(
@@ -1086,7 +1106,7 @@
scoped_refptr<GetCookiesWithInfoTask> task =
new GetCookiesWithInfoTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteCookieAsync(const GURL& url,
@@ -1095,14 +1115,13 @@
scoped_refptr<DeleteCookieTask> task =
new DeleteCookieTask(this, url, cookie_name, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DoCookieTask(
const scoped_refptr<CookieMonsterTask>& task_item) {
- InitIfNecessary();
-
{
+ InitIfNecessary();
base::AutoLock autolock(lock_);
if (!loaded_) {
queue_.push(task_item);
@@ -1113,6 +1132,34 @@
task_item->Run();
}
+void CookieMonster::DoCookieTaskForURL(
+ const scoped_refptr<CookieMonsterTask>& task_item,
+ const GURL& url) {
+ {
+ base::AutoLock autolock(lock_);
+ InitIfNecessary();
+ // If cookies for the requested domain key (eTLD+1) have been loaded from DB
+ // then run the task, otherwise load from DB.
+ if (!loaded_) {
+ // Checks if the domain key has been loaded.
+ std::string key(GetEffectiveDomain(url.scheme(), url.host()));
+ if (keys_loaded_.find(key) == keys_loaded_.end()) {
+ std::map<std::string, std::queue<scoped_refptr<CookieMonsterTask> > >
+ ::iterator it = tasks_queued_.find(key);
+ if (it == tasks_queued_.end()) {
+ store_->LoadCookiesForKey(key,
+ base::Bind(&CookieMonster::OnKeyLoaded, this, key));
+ it = tasks_queued_.insert(std::make_pair(key,
+ std::queue<scoped_refptr<CookieMonsterTask> >())).first;
+ }
+ it->second.push(task_item);
+ return;
+ }
+ }
+ }
+ task_item->Run();
+}
+
bool CookieMonster::SetCookieWithDetails(
const GURL& url, const std::string& name, const std::string& value,
const std::string& domain, const std::string& path,
@@ -1470,6 +1517,28 @@
InvokeQueue();
}
+void CookieMonster::OnKeyLoaded(const std::string& key,
erikwright (departed) 2011/10/04 19:55:02 Indentation: Either move "const ... cookies" to li
guohui 2011/10/06 15:40:00 Done.
+ const std::vector<CanonicalCookie*>& cookies) {
+ // This function does its own separate locking.
+ StoreLoadedCookies(cookies);
+ {
+ base::AutoLock autolock(lock_);
+ keys_loaded_.insert(key);
+ }
+ std::map<std::string, std::queue<scoped_refptr<CookieMonsterTask> > >
+ ::iterator it = tasks_queued_.find(key);
+ if (it != tasks_queued_.end())
+ while (true) {
erikwright (departed) 2011/10/04 19:55:02 The current implementation is a bit distasteful fo
guohui 2011/10/06 15:40:00 Done.
+ scoped_refptr<CookieMonsterTask> task = it->second.front();
+ task->Run();
+ it->second.pop();
+ if (it->second.empty()) {
+ tasks_queued_.erase(it);
+ break;
+ }
+ }
+}
+
void CookieMonster::StoreLoadedCookies(
const std::vector<CanonicalCookie*>& cookies) {
// Initialize the store and sync in any saved persistent cookies. We don't
@@ -1477,24 +1546,16 @@
// and sync'd.
base::AutoLock autolock(lock_);
- // Avoid ever letting cookies with duplicate creation times into the store;
- // that way we don't have to worry about what sections of code are safe
- // to call while it's in that state.
- std::set<int64> creation_times;
-
- // Presumably later than any access time in the store.
- Time earliest_access_time;
-
for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue();
- if (creation_times.insert(cookie_creation_time).second) {
+ if (creation_times_.insert(cookie_creation_time).second) {
InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
const Time cookie_access_time((*it)->LastAccessDate());
- if (earliest_access_time.is_null() ||
- cookie_access_time < earliest_access_time)
- earliest_access_time = cookie_access_time;
+ if (earliest_access_time_.is_null() ||
+ cookie_access_time < earliest_access_time_)
+ earliest_access_time_ = cookie_access_time;
} else {
LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation "
"times in backing store: "
@@ -1507,12 +1568,12 @@
delete (*it);
}
}
- earliest_access_time_= earliest_access_time;
// After importing cookies from the PersistentCookieStore, verify that
// none of our other constraints are violated.
- //
// In particular, the backing store might have given us duplicate cookies.
+ // "Priority loaded" cookies will be validated more than once, but this is OK
+ // since they are expected to be much fewer than total DB.
EnsureCookiesMapIsValid();
}
@@ -1523,6 +1584,8 @@
base::AutoLock autolock(lock_);
if (queue_.empty()) {
loaded_ = true;
+ creation_times_.clear();
+ keys_loaded_.clear();
break;
}
request_task = queue_.front();

Powered by Google App Engine
This is Rietveld 408576698