diff options
author | guohui@google.com <guohui@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-15 03:51:52 +0000 |
---|---|---|
committer | guohui@google.com <guohui@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-15 03:51:52 +0000 |
commit | fe6e23dcb40fe2731e42a1daf55a2268c8d0b5e7 (patch) | |
tree | a44bea8ac8e5ff0e5fcfada0becdc85965220180 /chrome | |
parent | 2255827f95cb9eb7abbefbcf5d98dec82daf526c (diff) | |
download | chromium_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.cc | 4 | ||||
-rw-r--r-- | chrome/browser/net/sqlite_persistent_cookie_store.cc | 276 | ||||
-rw-r--r-- | chrome/browser/net/sqlite_persistent_cookie_store.h | 7 | ||||
-rw-r--r-- | chrome/browser/net/sqlite_persistent_cookie_store_perftest.cc | 114 | ||||
-rw-r--r-- | chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc | 114 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 3 |
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', |