summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-20 13:02:53 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-20 13:02:53 +0000
commit6eea807ff6ac38e61ff3e6721c1c0acaa6f213d2 (patch)
tree6efc69bc9671dcbbc54d2d72ce493aa2a35d6a60 /webkit
parent7f9a8e49ef9340c838562c0d4fa0750e8c172d43 (diff)
downloadchromium_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.cc54
-rw-r--r--webkit/quota/quota_database.h11
-rw-r--r--webkit/quota/quota_manager.cc98
-rw-r--r--webkit/quota/quota_manager.h1
-rw-r--r--webkit/quota/quota_manager_unittest.cc126
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