diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 13:02:53 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 13:02:53 +0000 |
commit | 6eea807ff6ac38e61ff3e6721c1c0acaa6f213d2 (patch) | |
tree | 6efc69bc9671dcbbc54d2d72ce493aa2a35d6a60 /webkit | |
parent | 7f9a8e49ef9340c838562c0d4fa0750e8c172d43 (diff) | |
download | chromium_src-6eea807ff6ac38e61ff3e6721c1c0acaa6f213d2.zip chromium_src-6eea807ff6ac38e61ff3e6721c1c0acaa6f213d2.tar.gz chromium_src-6eea807ff6ac38e61ff3e6721c1c0acaa6f213d2.tar.bz2 |
Implement NotifyStorageAccessed
BUG=61676
TEST=to be added
Review URL: http://codereview.chromium.org/7011033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/quota/quota_database.cc | 54 | ||||
-rw-r--r-- | webkit/quota/quota_database.h | 11 | ||||
-rw-r--r-- | webkit/quota/quota_manager.cc | 98 | ||||
-rw-r--r-- | webkit/quota/quota_manager.h | 1 | ||||
-rw-r--r-- | webkit/quota/quota_manager_unittest.cc | 126 |
5 files changed, 244 insertions, 46 deletions
diff --git a/webkit/quota/quota_database.cc b/webkit/quota/quota_database.cc index 50a9ed2..52caf2e 100644 --- a/webkit/quota/quota_database.cc +++ b/webkit/quota/quota_database.cc @@ -13,6 +13,7 @@ #include "app/sql/transaction.h" #include "base/auto_reset.h" #include "base/file_util.h" +#include "base/time.h" #include "googleurl/src/gurl.h" namespace { @@ -90,6 +91,8 @@ std::string GetGlobalQuotaKey(quota::StorageType type) { return std::string(); } +const int kCommitIntervalMs = 30000; + } // anonymous namespace namespace quota { @@ -101,6 +104,9 @@ QuotaDatabase::QuotaDatabase(const FilePath& path) } QuotaDatabase::~QuotaDatabase() { + if (db_.get()) { + db_->CommitTransaction(); + } } void QuotaDatabase::CloseConnection() { @@ -138,10 +144,6 @@ bool QuotaDatabase::SetHostQuota( if (!LazyOpen(true)) return false; - sql::Transaction transaction(db_.get()); - if (!transaction.Begin()) - return false; - sql::Statement statement; int64 dummy; @@ -167,7 +169,8 @@ bool QuotaDatabase::SetHostQuota( if (!statement.Run()) return false; - return transaction.Commit(); + ScheduleCommit(); + return true; } bool QuotaDatabase::SetOriginLastAccessTime( @@ -175,10 +178,6 @@ bool QuotaDatabase::SetOriginLastAccessTime( if (!LazyOpen(true)) return false; - sql::Transaction transaction(db_.get()); - if (!transaction.Begin()) - return false; - sql::Statement statement; int used_count = 0; @@ -206,7 +205,8 @@ bool QuotaDatabase::SetOriginLastAccessTime( if (!statement.Run()) return false; - return transaction.Commit(); + ScheduleCommit(); + return true; } bool QuotaDatabase::RegisterOrigins(const std::set<GURL>& origins, @@ -257,7 +257,11 @@ bool QuotaDatabase::DeleteHostQuota( statement.BindString(0, host); statement.BindInt(1, static_cast<int>(type)); - return statement.Run(); + if (!statement.Run()) + return false; + + ScheduleCommit(); + return true; } bool QuotaDatabase::DeleteOriginLastAccessTime( @@ -275,7 +279,11 @@ bool QuotaDatabase::DeleteOriginLastAccessTime( statement.BindString(0, origin.spec()); statement.BindInt(1, static_cast<int>(type)); - return statement.Run(); + if (!statement.Run()) + return false; + + ScheduleCommit(); + return true; } bool QuotaDatabase::GetGlobalQuota(StorageType type, int64* quota) { @@ -334,6 +342,25 @@ bool QuotaDatabase::SetOriginDatabaseBootstrapped(bool bootstrap_flag) { return meta_table_->SetValue(kIsOriginTableBootstrapped, bootstrap_flag); } +void QuotaDatabase::Commit() { + if (!db_.get()) + return; + + // Note: for now this will be called only by ScheduleCommit, but when it + // becomes untrue we should call timer_.Stop() here. + DCHECK(!timer_.IsRunning()); + + db_->CommitTransaction(); + db_->BeginTransaction(); +} + +void QuotaDatabase::ScheduleCommit() { + if (timer_.IsRunning()) + return; + timer_.Start(base::TimeDelta::FromMilliseconds(kCommitIntervalMs), this, + &QuotaDatabase::Commit); +} + bool QuotaDatabase::FindOriginUsedCount( const GURL& origin, StorageType type, int* used_count) { DCHECK(used_count); @@ -394,6 +421,9 @@ bool QuotaDatabase::LazyOpen(bool create_if_needed) { return false; } + // Start a long-running transaction. + db_->BeginTransaction(); + return true; } diff --git a/webkit/quota/quota_database.h b/webkit/quota/quota_database.h index e18f338..32560b5 100644 --- a/webkit/quota/quota_database.h +++ b/webkit/quota/quota_database.h @@ -12,7 +12,7 @@ #include "base/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" -#include "base/time.h" +#include "base/timer.h" #include "webkit/quota/quota_types.h" namespace sql { @@ -66,6 +66,13 @@ class QuotaDatabase { bool SetOriginDatabaseBootstrapped(bool bootstrap_flag); private: + // For long-running transactions support. We always keep a transaction open + // so that multiple transactions can be batched. They are flushed + // with a delay after a modification has been made. We support neither + // nested transactions nor rollback (as we don't need them for now). + void Commit(); + void ScheduleCommit(); + bool FindOriginUsedCount(const GURL& origin, StorageType type, int* used_count); @@ -82,6 +89,8 @@ class QuotaDatabase { bool is_recreating_; bool is_disabled_; + base::OneShotTimer<QuotaDatabase> timer_; + friend class QuotaDatabaseTest; DISALLOW_COPY_AND_ASSIGN(QuotaDatabase); diff --git a/webkit/quota/quota_manager.cc b/webkit/quota/quota_manager.cc index 2d24e0b..7714a36 100644 --- a/webkit/quota/quota_manager.cc +++ b/webkit/quota/quota_manager.cc @@ -592,6 +592,33 @@ class QuotaManager::AvailableSpaceQueryTask : public QuotaThreadTask { scoped_ptr<AvailableSpaceCallback> callback_; }; +class QuotaManager::OriginAccessRecordDatabaseTask + : public QuotaManager::DatabaseTaskBase { + public: + OriginAccessRecordDatabaseTask( + QuotaManager* manager, + QuotaDatabase* database, + scoped_refptr<base::MessageLoopProxy> db_message_loop, + const GURL& origin, + StorageType type) + : DatabaseTaskBase(manager, database, db_message_loop), + origin_(origin), + type_(type) {} + + protected: + virtual void RunOnTargetThread() OVERRIDE { + if (!database()->SetOriginLastAccessTime( + origin_, type_, base::Time::Now())) { + set_db_disabled(true); + } + } + virtual void DatabaseTaskCompleted() OVERRIDE {} + + private: + GURL origin_; + StorageType type_; +}; + // QuotaManager --------------------------------------------------------------- QuotaManager::QuotaManager(bool is_incognito, @@ -654,38 +681,6 @@ void QuotaManager::RequestQuota( delete callback; } -void QuotaManager::NotifyStorageAccessed( - QuotaClient::ID client_id, - const GURL& origin, StorageType type) { - if (type == kStorageTypeTemporary && lru_origin_callback_.get()) { - // Record the accessed origins while GetLRUOrigin task is runing - // to filter out them from eviction. - access_notified_origins_.insert(origin); - } - - // TODO(michaeln): write me -} - -void QuotaManager::NotifyStorageModified( - QuotaClient::ID client_id, - const GURL& origin, StorageType type, int64 delta) { - LazyInitialize(); - GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta); -} - -void QuotaManager::NotifyOriginInUse(const GURL& origin) { - DCHECK(io_thread_->BelongsToCurrentThread()); - origins_in_use_[origin]++; -} - -void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) { - DCHECK(io_thread_->BelongsToCurrentThread()); - DCHECK(IsOriginInUse(origin)); - int& count = origins_in_use_[origin]; - if (--count == 0) - origins_in_use_.erase(origin); -} - void QuotaManager::GetAvailableSpace(AvailableSpaceCallback* callback) { scoped_refptr<AvailableSpaceQueryTask> task( new AvailableSpaceQueryTask(this, db_thread_, profile_path_, callback)); @@ -796,6 +791,44 @@ void QuotaManager::RegisterClient(QuotaClient* client) { clients_.push_back(client); } +void QuotaManager::NotifyStorageAccessed( + QuotaClient::ID client_id, + const GURL& origin, StorageType type) { + LazyInitialize(); + if (type == kStorageTypeTemporary && lru_origin_callback_.get()) { + // Record the accessed origins while GetLRUOrigin task is runing + // to filter out them from eviction. + access_notified_origins_.insert(origin); + } + + if (db_disabled_) + return; + scoped_refptr<OriginAccessRecordDatabaseTask> task( + new OriginAccessRecordDatabaseTask( + this, database_.get(), db_thread_, origin, type)); + task->Start(); +} + +void QuotaManager::NotifyStorageModified( + QuotaClient::ID client_id, + const GURL& origin, StorageType type, int64 delta) { + LazyInitialize(); + GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta); +} + +void QuotaManager::NotifyOriginInUse(const GURL& origin) { + DCHECK(io_thread_->BelongsToCurrentThread()); + origins_in_use_[origin]++; +} + +void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) { + DCHECK(io_thread_->BelongsToCurrentThread()); + DCHECK(IsOriginInUse(origin)); + int& count = origins_in_use_[origin]; + if (--count == 0) + origins_in_use_.erase(origin); +} + UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const { switch (type) { case kStorageTypeTemporary: @@ -826,7 +859,6 @@ void QuotaManager::GetCachedOrigins( } } -// TODO(kinuko): add test for this. void QuotaManager::DeleteOriginFromDatabase( const GURL& origin, StorageType type) { LazyInitialize(); diff --git a/webkit/quota/quota_manager.h b/webkit/quota/quota_manager.h index 9df5463..c50124e 100644 --- a/webkit/quota/quota_manager.h +++ b/webkit/quota/quota_manager.h @@ -152,6 +152,7 @@ class QuotaManager : public QuotaTaskObserver, class GetLRUOriginTask; class OriginDeletionDatabaseTask; class TemporaryOriginsRegistrationTask; + class OriginAccessRecordDatabaseTask; class UsageAndQuotaDispatcherTask; class UsageAndQuotaDispatcherTaskForTemporary; diff --git a/webkit/quota/quota_manager_unittest.cc b/webkit/quota/quota_manager_unittest.cc index 7a3a036..87599ca 100644 --- a/webkit/quota/quota_manager_unittest.cc +++ b/webkit/quota/quota_manager_unittest.cc @@ -12,6 +12,7 @@ #include "base/scoped_temp_dir.h" #include "base/stl_util-inl.h" #include "base/sys_info.h" +#include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageQuotaError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageQuotaType.h" @@ -135,6 +136,7 @@ class QuotaManagerTest : public testing::Test { void DeleteClientOriginData(QuotaClient* client, const GURL& origin, StorageType type) { + DCHECK(client); quota_status_ = kQuotaStatusUnknown; client->DeleteOriginData(origin, type, callback_factory_.NewCallback( @@ -173,6 +175,31 @@ class QuotaManagerTest : public testing::Test { quota_manager_->GetCachedOrigins(type, origins); } + void NotifyStorageAccessed(QuotaClient* client, + const GURL& origin, + StorageType type) { + DCHECK(client); + quota_manager_->NotifyStorageAccessed(client->id(), origin, type); + } + + void DeleteOriginFromDatabase(const GURL& origin, StorageType type) { + quota_manager_->DeleteOriginFromDatabase(origin, type); + } + + void GetLRUOrigin(StorageType type) { + lru_origin_ = GURL(); + quota_manager_->GetLRUOrigin(type, + callback_factory_.NewCallback(&QuotaManagerTest::DidGetLRUOrigin)); + } + + void NotifyOriginInUse(const GURL& origin) { + quota_manager_->NotifyOriginInUse(origin); + } + + void NotifyOriginNoLongerInUse(const GURL& origin) { + quota_manager_->NotifyOriginNoLongerInUse(origin); + } + void DidGetUsageAndQuota(QuotaStatusCode status, int64 usage, int64 quota) { quota_status_ = status; usage_ = usage; @@ -220,6 +247,10 @@ class QuotaManagerTest : public testing::Test { available_space_ = available_space; } + void DidGetLRUOrigin(const GURL& origin) { + lru_origin_ = origin; + } + void set_additional_callback_count(int c) { additional_callback_count_ = c; } int additional_callback_count() const { return additional_callback_count_; } void DidGetUsageAndQuotaAdditional( @@ -236,6 +267,7 @@ class QuotaManagerTest : public testing::Test { int64 usage() const { return usage_; } int64 quota() const { return quota_; } int64 available_space() const { return available_space_; } + const GURL& lru_origin() const { return lru_origin_; } FilePath profile_path() const { return data_dir_.path(); } private: @@ -249,6 +281,7 @@ class QuotaManagerTest : public testing::Test { int64 usage_; int64 quota_; int64 available_space_; + GURL lru_origin_; int additional_callback_count_; @@ -891,4 +924,97 @@ TEST_F(QuotaManagerTest, GetCachedOrigins) { } } +TEST_F(QuotaManagerTest, NotifyAndLRUOrigin) { + static const MockOriginData kData[] = { + { "http://a.com/", kStorageTypeTemporary, 0 }, + { "http://a.com:1/", kStorageTypeTemporary, 0 }, + { "https://a.com/", kStorageTypeTemporary, 0 }, + { "http://b.com/", kStorageTypePersistent, 0 }, // persistent + { "http://c.com/", kStorageTypeTemporary, 0 }, + }; + MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData)); + RegisterClient(client); + + GURL origin; + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_TRUE(lru_origin().is_empty()); + + NotifyStorageAccessed(client, GURL("http://a.com/"), kStorageTypeTemporary); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("http://a.com/", lru_origin().spec()); + + NotifyStorageAccessed(client, GURL("http://b.com/"), kStorageTypePersistent); + NotifyStorageAccessed(client, GURL("https://a.com/"), kStorageTypeTemporary); + NotifyStorageAccessed(client, GURL("http://c.com/"), kStorageTypeTemporary); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("http://a.com/", lru_origin().spec()); + + DeleteOriginFromDatabase(lru_origin(), kStorageTypeTemporary); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("https://a.com/", lru_origin().spec()); + + DeleteOriginFromDatabase(lru_origin(), kStorageTypeTemporary); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("http://c.com/", lru_origin().spec()); +} + +TEST_F(QuotaManagerTest, GetLRUOriginWithOriginInUse) { + static const MockOriginData kData[] = { + { "http://a.com/", kStorageTypeTemporary, 0 }, + { "http://a.com:1/", kStorageTypeTemporary, 0 }, + { "https://a.com/", kStorageTypeTemporary, 0 }, + { "http://b.com/", kStorageTypePersistent, 0 }, // persistent + { "http://c.com/", kStorageTypeTemporary, 0 }, + }; + MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData)); + RegisterClient(client); + + GURL origin; + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_TRUE(lru_origin().is_empty()); + + NotifyStorageAccessed(client, GURL("http://a.com/"), kStorageTypeTemporary); + NotifyStorageAccessed(client, GURL("http://b.com/"), kStorageTypePersistent); + NotifyStorageAccessed(client, GURL("https://a.com/"), kStorageTypeTemporary); + NotifyStorageAccessed(client, GURL("http://c.com/"), kStorageTypeTemporary); + + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("http://a.com/", lru_origin().spec()); + + // Notify origin http://a.com is in use. + NotifyOriginInUse(GURL("http://a.com/")); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("https://a.com/", lru_origin().spec()); + + // Notify origin https://a.com is in use while GetLRUOrigin is running. + GetLRUOrigin(kStorageTypeTemporary); + NotifyOriginInUse(GURL("https://a.com/")); + MessageLoop::current()->RunAllPending(); + // Post-filtering must have excluded the returned origin, so we will + // see empty result here. + EXPECT_TRUE(lru_origin().is_empty()); + + // Notify access for http://c.com while GetLRUOrigin is running. + GetLRUOrigin(kStorageTypeTemporary); + NotifyStorageAccessed(client, GURL("http://c.com/"), kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + // Post-filtering must have excluded the returned origin, so we will + // see empty result here. + EXPECT_TRUE(lru_origin().is_empty()); + + NotifyOriginNoLongerInUse(GURL("http://a.com/")); + NotifyOriginNoLongerInUse(GURL("https://a.com/")); + GetLRUOrigin(kStorageTypeTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ("http://a.com/", lru_origin().spec()); +} + } // namespace quota |