summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorguohui@google.com <guohui@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-15 03:51:52 +0000
committerguohui@google.com <guohui@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-15 03:51:52 +0000
commitfe6e23dcb40fe2731e42a1daf55a2268c8d0b5e7 (patch)
treea44bea8ac8e5ff0e5fcfada0becdc85965220180 /chrome
parent2255827f95cb9eb7abbefbcf5d98dec82daf526c (diff)
downloadchromium_src-fe6e23dcb40fe2731e42a1daf55a2268c8d0b5e7.zip
chromium_src-fe6e23dcb40fe2731e42a1daf55a2268c8d0b5e7.tar.gz
chromium_src-fe6e23dcb40fe2731e42a1daf55a2268c8d0b5e7.tar.bz2
The change list splits loading of cookies from DB by the domain key(eTLD+1).
BUG=52909 TEST=NONE Review URL: http://codereview.chromium.org/7864008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105639 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/fast_shutdown_uitest.cc4
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.cc276
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.h7
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store_perftest.cc114
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc114
-rw-r--r--chrome/chrome_tests.gypi3
6 files changed, 446 insertions, 72 deletions
diff --git a/chrome/browser/fast_shutdown_uitest.cc b/chrome/browser/fast_shutdown_uitest.cc
index 3bb9298..a7f1c00 100644
--- a/chrome/browser/fast_shutdown_uitest.cc
+++ b/chrome/browser/fast_shutdown_uitest.cc
@@ -42,11 +42,11 @@ class FastShutdown : public UITest {
user_data_dir_.AppendASCII(chrome::kInitialProfile)
.Append(chrome::kCookieFilename)));
std::vector<net::CookieMonster::CanonicalCookie*> cookies;
- ASSERT_TRUE(cookie_store->Load(
+ cookie_store->Load(
base::Bind(&FastShutdown::LoadCookiesCallback,
base::Unretained(this),
MessageLoop::current(),
- base::Unretained(&cookies))));
+ base::Unretained(&cookies)));
// Will receive a QuitTask when LoadCookiesCallback is invoked.
MessageLoop::current()->Run();
*has_cookie = false;
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
index b2adff1..632802b 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
@@ -5,6 +5,9 @@
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include <list>
+#include <map>
+#include <set>
+#include <utility>
#include "base/basictypes.h"
#include "base/bind.h"
@@ -15,11 +18,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
+#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "content/browser/browser_thread.h"
#include "googleurl/src/gurl.h"
+#include "net/base/registry_controlled_domain.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
@@ -27,10 +32,24 @@
using base::Time;
// This class is designed to be shared between any calling threads and the
-// database thread. It batches operations and commits them on a timer.
-// This class expects to be Load()'ed once on any thread. Loading occurs
-// asynchronously on the DB thread and the caller will be notified on the IO
-// thread. Subsequent to loading, mutations may be queued by any thread using
+// database thread. It batches operations and commits them on a timer.
+//
+// SQLitePersistentCookieStore::Load is called to load all cookies. It
+// delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread
+// task to the DB thread. This task calls Backend::ChainLoadCookies(), which
+// repeatedly posts itself to the DB thread to load each eTLD+1's cookies in
+// separate tasks. When this is complete, Backend::NotifyOnIOThread is posted
+// to the IO thread, which notifies the caller of SQLitePersistentCookieStore::
+// Load that the load is complete.
+//
+// If a priority load request is invoked via SQLitePersistentCookieStore::
+// LoadCookiesForKey, it is delegated to Backend::LoadCookiesForKey, which posts
+// Backend::LoadKeyAndNotifyOnDBThread to the DB thread. That routine loads just
+// that single domain key (eTLD+1)'s cookies, and posts a Backend::
+// NotifyOnIOThread to the IO thread to notify the caller of
+// SQLitePersistentCookieStore::LoadCookiesForKey that that load is complete.
+//
+// Subsequent to loading, mutations may be queued by any thread using
// AddCookie, UpdateCookieAccessTime, and DeleteCookie. These are flushed to
// disk on the DB thread every 30 seconds, 512 operations, or call to Flush(),
// whichever occurs first.
@@ -41,11 +60,16 @@ class SQLitePersistentCookieStore::Backend
: path_(path),
db_(NULL),
num_pending_(0),
- clear_local_state_on_exit_(false) {
+ clear_local_state_on_exit_(false),
+ initialized_(false) {
}
- // Creates or load the SQLite database.
- bool Load(const LoadedCallback& loaded_callback);
+ // Creates or loads the SQLite database.
+ void Load(const LoadedCallback& loaded_callback);
+
+ // Loads cookies for the domain key (eTLD+1).
+ void LoadCookiesForKey(const std::string& domain,
+ const LoadedCallback& loaded_callback);
// Batch a cookie addition.
void AddCookie(const net::CookieMonster::CanonicalCookie& cc);
@@ -98,17 +122,30 @@ class SQLitePersistentCookieStore::Backend
};
private:
- // Creates or load the SQLite database on DB thread.
+ // Creates or loads the SQLite database on DB thread.
void LoadAndNotifyOnDBThread(const LoadedCallback& loaded_callback);
- // Notify the CookieMonster when loading complete.
+
+ // Loads cookies for the domain key (eTLD+1) on DB thread.
+ void LoadKeyAndNotifyOnDBThread(const std::string& domains,
+ const LoadedCallback& loaded_callback);
+
+ // Notifies the CookieMonster when loading completes for a specific domain key
+ // or for all domain keys. Triggers the callback and passes it all cookies
+ // that have been loaded from DB since last IO notification.
void NotifyOnIOThread(
const LoadedCallback& loaded_callback,
- bool load_success,
- const std::vector<net::CookieMonster::CanonicalCookie*>& cookies);
+ bool load_success);
+
// Initialize the data base.
bool InitializeDatabase();
- // Load cookies to the data base, and read cookies.
- bool LoadInternal(std::vector<net::CookieMonster::CanonicalCookie*>* cookies);
+
+ // Loads cookies for the next domain key from the DB, then either reschedules
+ // itself or schedules the provided callback to run on the IO thread (if all
+ // domains are loaded).
+ void ChainLoadCookies(const LoadedCallback& loaded_callback);
+
+ // Load all cookies for a set of domains/hosts
+ bool LoadCookiesForDomains(const std::set<std::string>& key);
// Batch a cookie operation (add or delete)
void BatchOperation(PendingOperation::OperationType op,
@@ -127,9 +164,21 @@ class SQLitePersistentCookieStore::Backend
PendingOperationsList::size_type num_pending_;
// True if the persistent store should be deleted upon destruction.
bool clear_local_state_on_exit_;
- // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|.
+ // Guard |cookies_|, |pending_|, |num_pending_| and
+ // |clear_local_state_on_exit_|.
base::Lock lock_;
+ // Temporary buffer for cookies loaded from DB. Accumulates cookies to reduce
+ // the number of messages sent to the IO thread. Sent back in response to
+ // individual load requests for domain keys or when all loading completes.
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies_;
+
+ // Map of domain keys(eTLD+1) to domains/hosts that are to be loaded from DB.
+ std::map<std::string, std::set<std::string> > keys_to_load_;
+
+ // Indicates if DB has been initialized.
+ bool initialized_;
+
DISALLOW_COPY_AND_ASSIGN(Backend);
};
@@ -167,43 +216,91 @@ bool InitTable(sql::Connection* db) {
// so we want those people to get it. Ignore errors, since it may exist.
db->Execute("CREATE INDEX IF NOT EXISTS cookie_times ON cookies"
" (creation_utc)");
+
+ db->Execute("CREATE INDEX IF NOT EXISTS domain ON cookies(host_key)");
+
return true;
}
} // namespace
-bool SQLitePersistentCookieStore::Backend::Load(
+void SQLitePersistentCookieStore::Backend::Load(
const LoadedCallback& loaded_callback) {
// This function should be called only once per instance.
DCHECK(!db_.get());
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
- base::Bind(&Backend::LoadAndNotifyOnDBThread, base::Unretained(this),
- loaded_callback));
- return true;
+ base::Bind(&Backend::LoadAndNotifyOnDBThread, this, loaded_callback));
+}
+
+void SQLitePersistentCookieStore::Backend::LoadCookiesForKey(
+ const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&Backend::LoadKeyAndNotifyOnDBThread, this,
+ key,
+ loaded_callback));
}
void SQLitePersistentCookieStore::Backend::LoadAndNotifyOnDBThread(
const LoadedCallback& loaded_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
- std::vector<net::CookieMonster::CanonicalCookie*> cookies;
- bool load_success = LoadInternal(&cookies);
+ if (!InitializeDatabase()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStore::Backend::NotifyOnIOThread,
+ this, loaded_callback, false));
+ } else {
+ ChainLoadCookies(loaded_callback);
+ }
+}
+
+void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyOnDBThread(
+ const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ bool success = false;
+ if (InitializeDatabase()) {
+ std::map<std::string, std::set<std::string> >::iterator
+ it = keys_to_load_.find(key);
+ if (it != keys_to_load_.end()) {
+ success = LoadCookiesForDomains(it->second);
+ keys_to_load_.erase(it);
+ } else {
+ success = true;
+ }
+ }
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
- &SQLitePersistentCookieStore::Backend::NotifyOnIOThread,
- base::Unretained(this), loaded_callback, load_success, cookies));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStore::Backend::NotifyOnIOThread,
+ this, loaded_callback, success));
}
void SQLitePersistentCookieStore::Backend::NotifyOnIOThread(
const LoadedCallback& loaded_callback,
- bool load_success,
- const std::vector<net::CookieMonster::CanonicalCookie*>& cookies) {
+ bool load_success) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies;
+ {
+ base::AutoLock locked(lock_);
+ cookies.swap(cookies_);
+ }
+
loaded_callback.Run(cookies);
}
bool SQLitePersistentCookieStore::Backend::InitializeDatabase() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ if (initialized_) {
+ return true;
+ }
+
const FilePath dir = path_.DirName();
if (!file_util::PathExists(dir) && !file_util::CreateDirectory(dir)) {
return false;
@@ -225,47 +322,108 @@ bool SQLitePersistentCookieStore::Backend::InitializeDatabase() {
}
db_->Preload();
+
+ // Retrieve all the domains
+ sql::Statement smt(db_->GetUniqueStatement(
+ "SELECT DISTINCT host_key FROM cookies"));
+
+ if (!smt) {
+ NOTREACHED() << "select statement prep failed";
+ db_.reset();
+ return false;
+ }
+
+ // Build a map of domain keys (always eTLD+1) to domains.
+ while (smt.Step()) {
+ std::string domain = smt.ColumnString(0);
+ std::string key =
+ net::RegistryControlledDomainService::GetDomainAndRegistry(domain);
+
+ std::map<std::string, std::set<std::string> >::iterator it =
+ keys_to_load_.find(key);
+ if (it == keys_to_load_.end())
+ it = keys_to_load_.insert(std::make_pair
+ (key, std::set<std::string>())).first;
+ it->second.insert(domain);
+ }
+
+ initialized_ = true;
return true;
}
-bool SQLitePersistentCookieStore::Backend::LoadInternal(
- std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
- if (!InitializeDatabase()) {
- return false;
+void SQLitePersistentCookieStore::Backend::ChainLoadCookies(
+ const LoadedCallback& loaded_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ bool load_success = true;
+
+ if (keys_to_load_.size() > 0) {
+ // Load cookies for the first domain key.
+ std::map<std::string, std::set<std::string> >::iterator
+ it = keys_to_load_.begin();
+ load_success = LoadCookiesForDomains(it->second);
+ keys_to_load_.erase(it);
}
- // Slurp all the cookies into the out-vector.
- sql::Statement smt(db_->GetUniqueStatement(
- "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, "
- "httponly, last_access_utc FROM cookies"));
+ // If load is successful and there are more domain keys to be loaded,
+ // then post a DB task to continue chain-load;
+ // Otherwise notify on IO thread.
+ if (load_success && keys_to_load_.size() > 0) {
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&Backend::ChainLoadCookies, this, loaded_callback));
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStore::Backend::NotifyOnIOThread,
+ this, loaded_callback, load_success));
+ }
+}
+
+bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
+ const std::set<std::string>& domains) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ sql::Statement smt(db_->GetCachedStatement(SQL_FROM_HERE,
+ "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, "
+ "httponly, last_access_utc FROM cookies WHERE host_key = ?"));
if (!smt) {
NOTREACHED() << "select statement prep failed";
db_.reset();
return false;
}
- while (smt.Step()) {
- scoped_ptr<net::CookieMonster::CanonicalCookie> cc(
- new net::CookieMonster::CanonicalCookie(
- // The "source" URL is not used with persisted cookies.
- GURL(), // Source
- smt.ColumnString(2), // name
- smt.ColumnString(3), // value
- smt.ColumnString(1), // domain
- smt.ColumnString(4), // path
- std::string(), // TODO(abarth): Persist mac_key
- std::string(), // TODO(abarth): Persist mac_algorithm
- Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
- Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc
- Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc
- smt.ColumnInt(6) != 0, // secure
- smt.ColumnInt(7) != 0, // httponly
- true)); // has_expires
- DLOG_IF(WARNING,
- cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
- cookies->push_back(cc.release());
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies;
+ std::set<std::string>::const_iterator it = domains.begin();
+ for (; it != domains.end(); ++it) {
+ smt.BindString(0, *it);
+ while (smt.Step()) {
+ scoped_ptr<net::CookieMonster::CanonicalCookie> cc(
+ new net::CookieMonster::CanonicalCookie(
+ // The "source" URL is not used with persisted cookies.
+ GURL(), // Source
+ smt.ColumnString(2), // name
+ smt.ColumnString(3), // value
+ smt.ColumnString(1), // domain
+ smt.ColumnString(4), // path
+ std::string(), // TODO(abarth): Persist mac_key
+ std::string(), // TODO(abarth): Persist mac_algorithm
+ Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
+ Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc
+ Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc
+ smt.ColumnInt(6) != 0, // secure
+ smt.ColumnInt(7) != 0, // httponly
+ true)); // has_expires
+ DLOG_IF(WARNING,
+ cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
+ cookies.push_back(cc.release());
+ }
+ smt.Reset();
+ }
+ {
+ base::AutoLock locked(lock_);
+ cookies_.insert(cookies_.end(), cookies.begin(), cookies.end());
}
-
return true;
}
@@ -534,8 +692,14 @@ SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
}
}
-bool SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
- return backend_->Load(loaded_callback);
+void SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
+ backend_->Load(loaded_callback);
+}
+
+void SQLitePersistentCookieStore::LoadCookiesForKey(
+ const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ backend_->LoadCookiesForKey(key, loaded_callback);
}
void SQLitePersistentCookieStore::AddCookie(
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.h b/chrome/browser/net/sqlite_persistent_cookie_store.h
index 12a7de5..a634f4c 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.h
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.h
@@ -11,10 +11,12 @@
#include <string>
#include <vector>
+#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "net/base/cookie_monster.h"
class FilePath;
+class Task;
// Implements the PersistentCookieStore interface in terms of a SQLite database.
// For documentation about the actual member functions consult the documentation
@@ -25,7 +27,10 @@ class SQLitePersistentCookieStore
explicit SQLitePersistentCookieStore(const FilePath& path);
virtual ~SQLitePersistentCookieStore();
- virtual bool Load(const LoadedCallback& loaded_callback) OVERRIDE;
+ virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& callback) OVERRIDE;
virtual void AddCookie(
const net::CookieMonster::CanonicalCookie& cc) OVERRIDE;
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store_perftest.cc b/chrome/browser/net/sqlite_persistent_cookie_store_perftest.cc
new file mode 100644
index 0000000..03de457
--- /dev/null
+++ b/chrome/browser/net/sqlite_persistent_cookie_store_perftest.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/perftimer.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/thread_test_helper.h"
+#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
+#include "chrome/common/chrome_constants.h"
+#include "content/browser/browser_thread.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class SQLitePersistentCookieStorePerfTest : public testing::Test {
+ public:
+ SQLitePersistentCookieStorePerfTest()
+ : db_thread_(BrowserThread::DB),
+ io_thread_(BrowserThread::IO),
+ loaded_event_(false, false),
+ key_loaded_event_(false, false) {
+ }
+
+ void OnLoaded(
+ const std::vector<net::CookieMonster::CanonicalCookie*>& cookies) {
+ cookies_ = cookies;
+ loaded_event_.Signal();
+ }
+
+ void OnKeyLoaded(
+ const std::vector<net::CookieMonster::CanonicalCookie*>& cookies) {
+ cookies_ = cookies;
+ key_loaded_event_.Signal();
+ }
+
+ void Load() {
+ store_->Load(base::Bind(&SQLitePersistentCookieStorePerfTest::OnLoaded,
+ base::Unretained(this)));
+ loaded_event_.Wait();
+ }
+
+ virtual void SetUp() {
+ db_thread_.Start();
+ io_thread_.Start();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies;
+ Load();
+ ASSERT_EQ(0u, cookies_.size());
+ // Creates 15000 cookies from 300 eTLD+1s.
+ base::Time t = base::Time::Now();
+ for (int domain_num = 0; domain_num < 300; domain_num++) {
+ std::string domain_name(base::StringPrintf(".domain_%d.com", domain_num));
+ GURL gurl("www" + domain_name);
+ for (int cookie_num = 0; cookie_num < 50; ++cookie_num) {
+ t += base::TimeDelta::FromInternalValue(10);
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie(gurl,
+ base::StringPrintf("Cookie_%d", cookie_num), "1",
+ domain_name, "/", std::string(), std::string(),
+ t, t, t, false, false, true));
+ }
+ }
+ // Replace the store effectively destroying the current one and forcing it
+ // to write it's data to disk.
+ store_ = NULL;
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
+ // Make sure we wait until the destructor has run.
+ ASSERT_TRUE(helper->Run());
+
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+ }
+
+ protected:
+ BrowserThread db_thread_;
+ BrowserThread io_thread_;
+ base::WaitableEvent loaded_event_;
+ base::WaitableEvent key_loaded_event_;
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies_;
+ ScopedTempDir temp_dir_;
+ scoped_refptr<SQLitePersistentCookieStore> store_;
+};
+
+// Test the performance of priority load of cookies for a specfic domain key
+TEST_F(SQLitePersistentCookieStorePerfTest, TestLoadForKeyPerformance) {
+ for (int domain_num = 0; domain_num < 3; ++domain_num) {
+ std::string domain_name(base::StringPrintf("domain_%d.com", domain_num));
+ PerfTimeLogger timer(
+ ("Load cookies for the eTLD+1 " + domain_name).c_str());
+ store_->LoadCookiesForKey(domain_name,
+ base::Bind(&SQLitePersistentCookieStorePerfTest::OnKeyLoaded,
+ base::Unretained(this)));
+ key_loaded_event_.Wait();
+ timer.Done();
+
+ ASSERT_EQ(50U, cookies_.size());
+ }
+}
+
+// Test the performance of load
+TEST_F(SQLitePersistentCookieStorePerfTest, TestLoadPerformance) {
+ PerfTimeLogger timer("Load all cookies");
+ Load();
+ timer.Done();
+
+ ASSERT_EQ(15000U, cookies_.size());
+}
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc b/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc
index 942ca83..8e0109d 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc
@@ -23,23 +23,34 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
: ui_thread_(BrowserThread::UI),
db_thread_(BrowserThread::DB),
io_thread_(BrowserThread::IO),
- event_(false, false) {
+ loaded_event_(false, false),
+ key_loaded_event_(false, false),
+ db_thread_event_(true, false) {
}
- protected:
void OnLoaded(
const std::vector<net::CookieMonster::CanonicalCookie*>& cookies) {
cookies_ = cookies;
- event_.Signal();
+ loaded_event_.Signal();
+ }
+
+ void OnKeyLoaded(
+ const std::vector<net::CookieMonster::CanonicalCookie*>& cookies) {
+ cookies_ = cookies;
+ key_loaded_event_.Signal();
}
- bool Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
- bool result =
- store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
+ void Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
+ store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
base::Unretained(this)));
- event_.Wait();
+ loaded_event_.Wait();
*cookies = cookies_;
- return result;
+ }
+
+ // We have to create this method to wrap WaitableEvent::Wait, since we cannot
+ // bind a non-void returning method as a Closure.
+ void WaitOnDBEvent() {
+ db_thread_event_.Wait();
}
virtual void SetUp() {
@@ -50,7 +61,7 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
store_ = new SQLitePersistentCookieStore(
temp_dir_.path().Append(chrome::kCookieFilename));
std::vector<net::CookieMonster::CanonicalCookie*> cookies;
- ASSERT_TRUE(Load(&cookies));
+ Load(&cookies);
ASSERT_EQ(0u, cookies.size());
// Make sure the store gets written at least once.
store_->AddCookie(
@@ -62,10 +73,13 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
false, false, true));
}
+ protected:
BrowserThread ui_thread_;
BrowserThread db_thread_;
BrowserThread io_thread_;
- base::WaitableEvent event_;
+ base::WaitableEvent loaded_event_;
+ base::WaitableEvent key_loaded_event_;
+ base::WaitableEvent db_thread_event_;
std::vector<net::CookieMonster::CanonicalCookie*> cookies_;
ScopedTempDir temp_dir_;
scoped_refptr<SQLitePersistentCookieStore> store_;
@@ -118,7 +132,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
temp_dir_.path().Append(chrome::kCookieFilename));
// Reload and test for persistence
- ASSERT_TRUE(Load(&cookies));
+ Load(&cookies);
ASSERT_EQ(1U, cookies.size());
ASSERT_STREQ("http://foo.bar", cookies[0]->Domain().c_str());
ASSERT_STREQ("A", cookies[0]->Name().c_str());
@@ -135,10 +149,86 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
temp_dir_.path().Append(chrome::kCookieFilename));
// Reload and check if the cookie has been removed.
- ASSERT_TRUE(Load(&cookies));
+ Load(&cookies);
ASSERT_EQ(0U, cookies.size());
}
+// Test that priority load of cookies for a specfic domain key could be
+// completed before the entire store is loaded
+TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
+ base::Time t = base::Time::Now() + base::TimeDelta::FromInternalValue(10);
+ // A foo.bar cookie was already added in setup.
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie(GURL(), "A", "B",
+ "www.aaa.com", "/",
+ std::string(), std::string(),
+ t, t, t, false, false, true));
+ t += base::TimeDelta::FromInternalValue(10);
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie(GURL(), "A", "B",
+ "travel.aaa.com", "/",
+ std::string(), std::string(),
+ t, t, t, false, false, true));
+ t += base::TimeDelta::FromInternalValue(10);
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie(GURL(), "A", "B",
+ "www.bbb.com", "/",
+ std::string(), std::string(),
+ t, t, t, false, false, true));
+ store_ = NULL;
+
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
+ // Make sure we wait until the destructor has run.
+ ASSERT_TRUE(helper->Run());
+
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+ // Posting a blocking task to db_thread_ makes sure that the DB thread waits
+ // until both Load and LoadCookiesForKey have been posted to its task queue.
+ db_thread_.PostTask(BrowserThread::DB, FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
+ base::Unretained(this)));
+ store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
+ base::Unretained(this)));
+ store_->LoadCookiesForKey("aaa.com",
+ base::Bind(&SQLitePersistentCookieStoreTest::OnKeyLoaded,
+ base::Unretained(this)));
+ db_thread_.PostTask(BrowserThread::DB, FROM_HERE,
+ base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
+ base::Unretained(this)));
+
+ // Now the DB-thread queue contains:
+ // (active:)
+ // 1. Wait (on db_event)
+ // (pending:)
+ // 2. "Init And Chain-Load First Domain"
+ // 3. Priority Load (aaa.com)
+ // 4. Wait (on db_event)
+ db_thread_event_.Signal();
+ key_loaded_event_.Wait();
+ ASSERT_EQ(loaded_event_.IsSignaled(), false);
+ std::set<std::string> cookies_loaded;
+ for (std::vector<net::CookieMonster::CanonicalCookie*>::iterator
+ it = cookies_.begin(); it != cookies_.end(); ++it)
+ cookies_loaded.insert((*it)->Domain().c_str());
+ ASSERT_GT(4U, cookies_loaded.size());
+ ASSERT_EQ(cookies_loaded.find("www.aaa.com") != cookies_loaded.end(), true);
+ ASSERT_EQ(cookies_loaded.find("travel.aaa.com") != cookies_loaded.end(),
+ true);
+
+ db_thread_event_.Signal();
+ loaded_event_.Wait();
+ for (std::vector<net::CookieMonster::CanonicalCookie*>::iterator
+ it = cookies_.begin(); it != cookies_.end(); ++it)
+ cookies_loaded.insert((*it)->Domain().c_str());
+ ASSERT_EQ(4U, cookies_loaded.size());
+ ASSERT_EQ(cookies_loaded.find("http://foo.bar") != cookies_loaded.end(),
+ true);
+ ASSERT_EQ(cookies_loaded.find("www.bbb.com") != cookies_loaded.end(), true);
+}
+
// Test that we can force the database to be written by calling Flush().
TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
// File timestamps don't work well on all platforms, so we'll determine
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 6b6f6f7..7649d19 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -3676,7 +3676,8 @@
'../webkit/support/webkit_support.gyp:glue',
],
'sources': [
- 'browser/safe_browsing/filter_false_positive_perftest.cc',
+ 'browser/net/sqlite_origin_bound_cert_store_unittest.cc',
+ 'browser/safe_browsing/filter_false_positive_perftest.cc',
'browser/visitedlink/visitedlink_perftest.cc',
'common/json_value_serializer_perftest.cc',
'test/perf/perftests.cc',