diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-10 21:43:35 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-10 21:43:35 +0000 |
commit | 3bbe097b9a6e516d3f1f60bec571033820038b3b (patch) | |
tree | 7f0f727d11437ee9031fa9f39491de4da21288e0 | |
parent | 3b06fe1d485105136c5c958d1cb27a3bb4277d16 (diff) | |
download | chromium_src-3bbe097b9a6e516d3f1f60bec571033820038b3b.zip chromium_src-3bbe097b9a6e516d3f1f60bec571033820038b3b.tar.gz chromium_src-3bbe097b9a6e516d3f1f60bec571033820038b3b.tar.bz2 |
Implementation of DatabaseQuotaClient for the WebSQLDatabase system.
In this CL the the 'client' interface is implemented, but the QuotaManager is not notified of changes as they occur, and the hard-coded 5MB limits imposed by the DB system are still being used.
BUG=61676
TEST=database_quota_client_unittest.cc
Review URL: http://codereview.chromium.org/6904111
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84865 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/profiles/profile.cc | 10 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_impl.cc | 10 | ||||
-rw-r--r-- | chrome/test/testing_profile.cc | 2 | ||||
-rw-r--r-- | webkit/database/database_quota_client.cc | 218 | ||||
-rw-r--r-- | webkit/database/database_quota_client.h | 81 | ||||
-rw-r--r-- | webkit/database/database_quota_client_unittest.cc | 218 | ||||
-rw-r--r-- | webkit/database/database_tracker.cc | 78 | ||||
-rw-r--r-- | webkit/database/database_tracker.h | 24 | ||||
-rw-r--r-- | webkit/database/database_tracker_unittest.cc | 6 | ||||
-rw-r--r-- | webkit/database/webkit_database.gypi | 3 | ||||
-rw-r--r-- | webkit/support/simple_database_system.cc | 2 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gypi | 1 |
12 files changed, 629 insertions, 24 deletions
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index bcb812a..20e84ee 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc @@ -287,10 +287,7 @@ class OffTheRecordProfileImpl : public Profile, } virtual webkit_database::DatabaseTracker* GetDatabaseTracker() { - if (!db_tracker_.get()) { - db_tracker_ = new webkit_database::DatabaseTracker( - GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); - } + CreateQuotaManagerAndClients(); return db_tracker_; } @@ -699,6 +696,7 @@ class OffTheRecordProfileImpl : public Profile, void CreateQuotaManagerAndClients() { if (quota_manager_.get()) { DCHECK(file_system_context_.get()); + DCHECK(db_tracker_.get()); return; } @@ -718,6 +716,10 @@ class OffTheRecordProfileImpl : public Profile, GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(), quota_manager_->proxy()); + db_tracker_ = new webkit_database::DatabaseTracker( + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(), + quota_manager_->proxy(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); } NotificationRegistrar registrar_; diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index ae2a519..e168882 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -727,10 +727,7 @@ ChromeAppCacheService* ProfileImpl::GetAppCacheService() { } webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() { - if (!db_tracker_) { - db_tracker_ = new webkit_database::DatabaseTracker( - GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy()); - } + CreateQuotaManagerAndClients(); return db_tracker_; } @@ -1273,6 +1270,7 @@ ExtensionPrefValueMap* ProfileImpl::GetExtensionPrefValueMap() { void ProfileImpl::CreateQuotaManagerAndClients() { if (quota_manager_.get()) { DCHECK(file_system_context_.get()); + DCHECK(db_tracker_.get()); return; } @@ -1292,6 +1290,10 @@ void ProfileImpl::CreateQuotaManagerAndClients() { GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(), quota_manager_->proxy()); + db_tracker_ = new webkit_database::DatabaseTracker( + GetPath(), IsOffTheRecord(), GetExtensionSpecialStoragePolicy(), + quota_manager_->proxy(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); } WebKitContext* ProfileImpl::GetWebKitContext() { diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc index 06c08d6..1dd64b4 100644 --- a/chrome/test/testing_profile.cc +++ b/chrome/test/testing_profile.cc @@ -417,7 +417,7 @@ ChromeAppCacheService* TestingProfile::GetAppCacheService() { webkit_database::DatabaseTracker* TestingProfile::GetDatabaseTracker() { if (!db_tracker_) { db_tracker_ = new webkit_database::DatabaseTracker( - GetPath(), false, GetExtensionSpecialStoragePolicy()); + GetPath(), false, GetExtensionSpecialStoragePolicy(), NULL, NULL); } return db_tracker_; } diff --git a/webkit/database/database_quota_client.cc b/webkit/database/database_quota_client.cc new file mode 100644 index 0000000..4f3da01 --- /dev/null +++ b/webkit/database/database_quota_client.cc @@ -0,0 +1,218 @@ +// 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 "webkit/database/database_quota_client.h" + +#include "base/message_loop_proxy.h" +#include "net/base/net_util.h" +#include "webkit/database/database_tracker.h" +#include "webkit/database/database_util.h" + +using quota::QuotaClient; + +namespace webkit_database { + +// Helper tasks --------------------------------------------------------------- + +class DatabaseQuotaClient::HelperTask : public quota::QuotaThreadTask { + protected: + HelperTask( + DatabaseQuotaClient* client, + scoped_refptr<base::MessageLoopProxy> db_tracker_thread) + : QuotaThreadTask(client, db_tracker_thread), + client_(client), db_tracker_(client->db_tracker_) { + } + + DatabaseQuotaClient* client_; + scoped_refptr<DatabaseTracker> db_tracker_; +}; + +class DatabaseQuotaClient::GetOriginUsageTask : public HelperTask { + public: + GetOriginUsageTask( + DatabaseQuotaClient* client, + scoped_refptr<base::MessageLoopProxy> db_tracker_thread, + const GURL& origin_url) + : HelperTask(client, db_tracker_thread), + origin_url_(origin_url), usage_(0) { + } + + private: + virtual void RunOnTargetThread() OVERRIDE { + OriginInfo info; + if (db_tracker_->GetOriginInfo( + DatabaseUtil::GetOriginIdentifier(origin_url_), + &info)) { + usage_ = info.TotalSize(); + } + } + virtual void Completed() OVERRIDE { + client_->DidGetOriginUsage(origin_url_, usage_); + } + GURL origin_url_; + int64 usage_; +}; + +class DatabaseQuotaClient::GetOriginsTaskBase : public HelperTask { + protected: + GetOriginsTaskBase( + DatabaseQuotaClient* client, + scoped_refptr<base::MessageLoopProxy> db_tracker_thread) + : HelperTask(client, db_tracker_thread) { + } + + virtual bool ShouldAddOrigin(const GURL& origin) = 0; + + virtual void RunOnTargetThread() OVERRIDE { + std::vector<string16> origin_identifiers; + if (db_tracker_->GetAllOriginIdentifiers(&origin_identifiers)) { + for (std::vector<string16>::const_iterator iter = + origin_identifiers.begin(); + iter != origin_identifiers.end(); ++iter) { + GURL origin = DatabaseUtil::GetOriginFromIdentifier(*iter); + if (ShouldAddOrigin(origin)) + origins_.insert(origin); + } + } + } + + std::set<GURL> origins_; +}; + +class DatabaseQuotaClient::GetAllOriginsTask : public GetOriginsTaskBase { + public: + GetAllOriginsTask( + DatabaseQuotaClient* client, + scoped_refptr<base::MessageLoopProxy> db_tracker_thread) + : GetOriginsTaskBase(client, db_tracker_thread) { + } + + protected: + virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { + return true; + } + virtual void Completed() OVERRIDE { + client_->DidGetAllOrigins(origins_); + } +}; + +class DatabaseQuotaClient::GetOriginsForHostTask : public GetOriginsTaskBase { + public: + GetOriginsForHostTask( + DatabaseQuotaClient* client, + scoped_refptr<base::MessageLoopProxy> db_tracker_thread, + const std::string& host) + : GetOriginsTaskBase(client, db_tracker_thread), + host_(host) { + } + + private: + virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { + return host_ == net::GetHostOrSpecFromURL(origin); + } + virtual void Completed() OVERRIDE { + client_->DidGetOriginsForHost(host_, origins_); + } + std::string host_; +}; + +// DatabaseQuotaClient -------------------------------------------------------- + +DatabaseQuotaClient::DatabaseQuotaClient( + base::MessageLoopProxy* db_tracker_thread, + DatabaseTracker* db_tracker) + : db_tracker_thread_(db_tracker_thread), db_tracker_(db_tracker) { +} + +DatabaseQuotaClient::~DatabaseQuotaClient() { +} + +QuotaClient::ID DatabaseQuotaClient::id() const { + return kDatabase; +} + +void DatabaseQuotaClient::OnQuotaManagerDestroyed() { + delete this; +} + +void DatabaseQuotaClient::GetOriginUsage( + const GURL& origin_url, + quota::StorageType type, + GetUsageCallback* callback_ptr) { + DCHECK(callback_ptr); + DCHECK(db_tracker_.get()); + scoped_ptr<GetUsageCallback> callback(callback_ptr); + + // All databases are in the temp namespace for now. + if (type != quota::kStorageTypeTemporary) { + callback->Run(0); + return; + } + + if (usage_for_origin_callbacks_.Add(origin_url, callback.release())) { + scoped_refptr<GetOriginUsageTask> task( + new GetOriginUsageTask(this, db_tracker_thread_, origin_url)); + task->Start(); + } +} + +void DatabaseQuotaClient::GetOriginsForType( + quota::StorageType type, + GetOriginsCallback* callback_ptr) { + DCHECK(callback_ptr); + DCHECK(db_tracker_.get()); + scoped_ptr<GetOriginsCallback> callback(callback_ptr); + + // All databases are in the temp namespace for now. + if (type != quota::kStorageTypeTemporary) { + callback->Run(std::set<GURL>()); + return; + } + + if (origins_for_type_callbacks_.Add(callback.release())) { + scoped_refptr<GetAllOriginsTask> task( + new GetAllOriginsTask(this, db_tracker_thread_)); + task->Start(); + } +} + +void DatabaseQuotaClient::GetOriginsForHost( + quota::StorageType type, + const std::string& host, + GetOriginsCallback* callback_ptr) { + DCHECK(callback_ptr); + DCHECK(db_tracker_.get()); + scoped_ptr<GetOriginsCallback> callback(callback_ptr); + + // All databases are in the temp namespace for now. + if (type != quota::kStorageTypeTemporary) { + callback->Run(std::set<GURL>()); + return; + } + + if (origins_for_host_callbacks_.Add(host, callback.release())) { + scoped_refptr<GetOriginsForHostTask> task( + new GetOriginsForHostTask(this, db_tracker_thread_, host)); + task->Start(); + } +} + +void DatabaseQuotaClient::DidGetOriginUsage( + const GURL& origin_url, int64 usage) { + DCHECK(usage_for_origin_callbacks_.HasCallbacks(origin_url)); + usage_for_origin_callbacks_.Run(origin_url, usage); +} + +void DatabaseQuotaClient::DidGetAllOrigins(const std::set<GURL>& origins) { + DCHECK(origins_for_type_callbacks_.HasCallbacks()); + origins_for_type_callbacks_.Run(origins); +} + +void DatabaseQuotaClient::DidGetOriginsForHost( + const std::string& host, const std::set<GURL>& origins) { + DCHECK(origins_for_host_callbacks_.HasCallbacks(host)); + origins_for_host_callbacks_.Run(host, origins); +} + +} // namespace webkit_database diff --git a/webkit/database/database_quota_client.h b/webkit/database/database_quota_client.h new file mode 100644 index 0000000..5733e57 --- /dev/null +++ b/webkit/database/database_quota_client.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef WEBKIT_DATABASE_DATABASE_QUOTA_CLIENT_H_ +#define WEBKIT_DATABASE_DATABASE_QUOTA_CLIENT_H_ + +#include <set> +#include <string> + +#include "base/memory/ref_counted.h" +#include "base/message_loop_proxy.h" +#include "webkit/quota/quota_client.h" +#include "webkit/quota/quota_task.h" +#include "webkit/quota/quota_types.h" + +namespace webkit_database { + +class DatabaseTracker; + +// A QuotaClient implementation to integrate WebSQLDatabases +// with the quota management system. This interface is used +// on the IO thread by the quota manager. +class DatabaseQuotaClient : public quota::QuotaClient, + public quota::QuotaTaskObserver { + public: + DatabaseQuotaClient( + base::MessageLoopProxy* tracker_thread, + DatabaseTracker* tracker); + virtual ~DatabaseQuotaClient(); + + // QuotaClient method overrides + virtual ID id() const OVERRIDE; + virtual void OnQuotaManagerDestroyed(); + virtual void GetOriginUsage(const GURL& origin_url, + quota::StorageType type, + GetUsageCallback* callback) OVERRIDE; + virtual void GetOriginsForType(quota::StorageType type, + GetOriginsCallback* callback) OVERRIDE; + virtual void GetOriginsForHost(quota::StorageType type, + const std::string& host, + GetOriginsCallback* callback) OVERRIDE; + private: + class HelperTask; + class GetOriginUsageTask; + class GetOriginsTaskBase; + class GetAllOriginsTask; + class GetOriginsForHostTask; + + typedef quota::CallbackQueueMap1 + <GetUsageCallback*, + GURL, // origin + int64 + > UsageForOriginCallbackMap; + typedef quota::CallbackQueue1 + <GetOriginsCallback*, + const std::set<GURL>& + > OriginsForTypeCallbackQueue; + typedef quota::CallbackQueueMap1 + <GetOriginsCallback*, + std::string, // host + const std::set<GURL>& + > OriginsForHostCallbackMap; + + void DidGetOriginUsage(const GURL& origin_url, int64 usage); + void DidGetAllOrigins(const std::set<GURL>& origins); + void DidGetOriginsForHost( + const std::string& host, const std::set<GURL>& origins); + + scoped_refptr<base::MessageLoopProxy> db_tracker_thread_; + scoped_refptr<DatabaseTracker> db_tracker_; // only used on its thread + UsageForOriginCallbackMap usage_for_origin_callbacks_; + OriginsForTypeCallbackQueue origins_for_type_callbacks_; + OriginsForHostCallbackMap origins_for_host_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(DatabaseQuotaClient); +}; + +} // namespace webkit_database + +#endif // WEBKIT_DATABASE_DATABASE_QUOTA_CLIENT_H_ diff --git a/webkit/database/database_quota_client_unittest.cc b/webkit/database/database_quota_client_unittest.cc new file mode 100644 index 0000000..38e3742 --- /dev/null +++ b/webkit/database/database_quota_client_unittest.cc @@ -0,0 +1,218 @@ +// 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 <map> + +#include "base/file_path.h" +#include "base/memory/scoped_callback_factory.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/database/database_quota_client.h" +#include "webkit/database/database_tracker.h" +#include "webkit/database/database_util.h" + +namespace webkit_database { + +// Declared to shorten the line lengths. +static const quota::StorageType kTemp = quota::kStorageTypeTemporary; +static const quota::StorageType kPerm = quota::kStorageTypePersistent; + +// Mock tracker class the mocks up those methods of the tracker +// that are used by the QuotaClient. +class MockDatabaseTracker : public DatabaseTracker { + public: + MockDatabaseTracker() + : DatabaseTracker(FilePath(), false, NULL, NULL, NULL) {} + + virtual ~MockDatabaseTracker() {} + + virtual bool GetOriginInfo( + const string16& origin_identifier, + OriginInfo* info) OVERRIDE { + std::map<GURL, MockOriginInfo>::const_iterator found = + mock_origin_infos_.find( + DatabaseUtil::GetOriginFromIdentifier(origin_identifier)); + if (found == mock_origin_infos_.end()) + return false; + *info = OriginInfo(found->second); + return true; + } + + virtual bool GetAllOriginIdentifiers( + std::vector<string16>* origins_identifiers) OVERRIDE { + std::map<GURL, MockOriginInfo>::const_iterator iter; + for (iter = mock_origin_infos_.begin(); + iter != mock_origin_infos_.end(); + ++iter) { + origins_identifiers->push_back(iter->second.GetOrigin()); + } + return true; + } + + virtual bool GetAllOriginsInfo( + std::vector<OriginInfo>* origins_info) OVERRIDE { + std::map<GURL, MockOriginInfo>::const_iterator iter; + for (iter = mock_origin_infos_.begin(); + iter != mock_origin_infos_.end(); + ++iter) { + origins_info->push_back(OriginInfo(iter->second)); + } + return true; + } + + void AddMockDatabase(const GURL& origin, const char* name, int size) { + MockOriginInfo& info = mock_origin_infos_[origin]; + info.set_origin(DatabaseUtil::GetOriginIdentifier(origin)); + info.AddMockDatabase(ASCIIToUTF16(name), size); + } + + private: + class MockOriginInfo : public OriginInfo { + public: + void set_origin(const string16& origin_id) { + origin_ = origin_id; + } + + void AddMockDatabase(const string16& name, int size) { + EXPECT_TRUE(database_info_.find(name) == database_info_.end()); + database_info_[name].first = size; + total_size_ += size; + } + }; + + std::map<GURL, MockOriginInfo> mock_origin_infos_; +}; + + +// Base class for our test fixtures. +class DatabaseQuotaClientTest : public testing::Test { + public: + const GURL kOriginA; + const GURL kOriginB; + const GURL kOriginOther; + + DatabaseQuotaClientTest() + : kOriginA("http://host"), + kOriginB("http://host:8000"), + kOriginOther("http://other"), + usage_(0), + mock_tracker_(new MockDatabaseTracker), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + } + + int64 GetOriginUsage( + quota::QuotaClient* client, + const GURL& origin, + quota::StorageType type) { + usage_ = 0; + client->GetOriginUsage(origin, type, + callback_factory_.NewCallback( + &DatabaseQuotaClientTest::OnGetOriginUsageComplete)); + MessageLoop::current()->RunAllPending(); + return usage_; + } + + const std::set<GURL>& GetOriginsForType( + quota::QuotaClient* client, + quota::StorageType type) { + origins_.clear(); + client->GetOriginsForType(type, + callback_factory_.NewCallback( + &DatabaseQuotaClientTest::OnGetOriginsComplete)); + MessageLoop::current()->RunAllPending(); + return origins_; + } + + const std::set<GURL>& GetOriginsForHost( + quota::QuotaClient* client, + quota::StorageType type, + const std::string& host) { + origins_.clear(); + client->GetOriginsForHost(type, host, + callback_factory_.NewCallback( + &DatabaseQuotaClientTest::OnGetOriginsComplete)); + MessageLoop::current()->RunAllPending(); + return origins_; + } + + MockDatabaseTracker* mock_tracker() { return mock_tracker_.get(); } + + + private: + void OnGetOriginUsageComplete(int64 usage) { + usage_ = usage; + } + + void OnGetOriginsComplete(const std::set<GURL>& origins) { + origins_ = origins; + } + + int64 usage_; + std::set<GURL> origins_; + scoped_refptr<MockDatabaseTracker> mock_tracker_; + base::ScopedCallbackFactory<DatabaseQuotaClientTest> callback_factory_; +}; + + +TEST_F(DatabaseQuotaClientTest, GetOriginUsage) { + DatabaseQuotaClient client( + base::MessageLoopProxy::CreateForCurrentThread(), + mock_tracker()); + + EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp)); + EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm)); + + mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); + EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp)); + EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm)); + + EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kPerm)); + EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kTemp)); +} + +TEST_F(DatabaseQuotaClientTest, GetOriginsForHost) { + DatabaseQuotaClient client( + base::MessageLoopProxy::CreateForCurrentThread(), + mock_tracker()); + + EXPECT_EQ(kOriginA.host(), kOriginB.host()); + EXPECT_NE(kOriginA.host(), kOriginOther.host()); + + std::set<GURL> origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); + EXPECT_TRUE(origins.empty()); + + mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); + origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); + EXPECT_EQ(origins.size(), 1ul); + EXPECT_TRUE(origins.find(kOriginA) != origins.end()); + + mock_tracker()->AddMockDatabase(kOriginB, "barDB", 1000); + origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); + EXPECT_EQ(origins.size(), 2ul); + EXPECT_TRUE(origins.find(kOriginA) != origins.end()); + EXPECT_TRUE(origins.find(kOriginB) != origins.end()); + + EXPECT_TRUE(GetOriginsForHost(&client, kPerm, kOriginA.host()).empty()); + EXPECT_TRUE(GetOriginsForHost(&client, kTemp, kOriginOther.host()).empty()); +} + +TEST_F(DatabaseQuotaClientTest, GetOriginsForType) { + DatabaseQuotaClient client( + base::MessageLoopProxy::CreateForCurrentThread(), + mock_tracker()); + + EXPECT_TRUE(GetOriginsForType(&client, kTemp).empty()); + EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty()); + + mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); + std::set<GURL> origins = GetOriginsForType(&client, kTemp); + EXPECT_EQ(origins.size(), 1ul); + EXPECT_TRUE(origins.find(kOriginA) != origins.end()); + + EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty()); +} + +} // namespace webkit_database diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc index 5911ad2..1dc29db 100644 --- a/webkit/database/database_tracker.cc +++ b/webkit/database/database_tracker.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -14,12 +14,15 @@ #include "app/sql/transaction.h" #include "base/basictypes.h" #include "base/file_util.h" +#include "base/message_loop_proxy.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "net/base/net_errors.h" +#include "webkit/database/database_quota_client.h" #include "webkit/database/database_util.h" #include "webkit/database/databases_table.h" #include "webkit/database/quota_table.h" +#include "webkit/quota/quota_manager.h" #include "webkit/quota/special_storage_policy.h" namespace { @@ -47,6 +50,10 @@ static const int kCurrentVersion = 2; static const int kCompatibleVersion = 1; static const char* kExtensionOriginIdentifierPrefix = "chrome-extension_"; +OriginInfo::OriginInfo() + : total_size_(0), + quota_(0) {} + OriginInfo::OriginInfo(const OriginInfo& origin_info) : origin_(origin_info.origin_), total_size_(origin_info.total_size_), @@ -83,7 +90,9 @@ OriginInfo::OriginInfo(const string16& origin, int64 total_size, int64 quota) DatabaseTracker::DatabaseTracker( const FilePath& profile_path, bool is_incognito, - quota::SpecialStoragePolicy* special_storage_policy) + quota::SpecialStoragePolicy* special_storage_policy, + quota::QuotaManagerProxy* quota_manager_proxy, + base::MessageLoopProxy* db_tracker_thread) : is_initialized_(false), is_incognito_(is_incognito), shutting_down_(false), @@ -96,7 +105,12 @@ DatabaseTracker::DatabaseTracker( meta_table_(NULL), default_quota_(5 * 1024 * 1024), special_storage_policy_(special_storage_policy), + quota_manager_proxy_(quota_manager_proxy), incognito_origin_directories_generator_(0) { + if (quota_manager_proxy) { + quota_manager_proxy->RegisterClient( + new DatabaseQuotaClient(db_tracker_thread, this)); + } } DatabaseTracker::~DatabaseTracker() { @@ -140,6 +154,17 @@ void DatabaseTracker::DatabaseModified(const string16& origin_identifier, int64 space_available = GetOriginSpaceAvailable(origin_identifier); FOR_EACH_OBSERVER(Observer, observers_, OnDatabaseSizeChanged( origin_identifier, database_name, updated_db_size, space_available)); + + if (quota_manager_proxy_) { + // TODO(michaeln): notify the quota manager + // CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); + // if (origin_info) + // quota_manager_proxy_->NotifyStorageConsumed( + // quota::QuotaClient::kDatabase, + // DatabaseUtil::GetOriginFromIdentifier(origin_identifier), + // quota::kStorageTypeTemporary, + // origin_info->TotalSize()); + } } void DatabaseTracker::DatabaseClosed(const string16& origin_identifier, @@ -259,14 +284,31 @@ FilePath DatabaseTracker::GetFullDBFilePath( UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name); } +bool DatabaseTracker::GetOriginInfo(const string16& origin_identifier, + OriginInfo* info) { + DCHECK(info); + CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier); + if (!cached_info) + return false; + *info = OriginInfo(*cached_info); + return true; +} + +bool DatabaseTracker::GetAllOriginIdentifiers( + std::vector<string16>* origin_identifiers) { + DCHECK(origin_identifiers); + DCHECK(origin_identifiers->empty()); + if (!LazyInit()) + return false; + return databases_table_->GetAllOrigins(origin_identifiers); +} + bool DatabaseTracker::GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) { DCHECK(origins_info); DCHECK(origins_info->empty()); - if (!LazyInit()) - return false; std::vector<string16> origins; - if (!databases_table_->GetAllOrigins(&origins)) + if (!GetAllOriginIdentifiers(&origins)) return false; for (std::vector<string16>::const_iterator it = origins.begin(); @@ -314,11 +356,21 @@ bool DatabaseTracker::DeleteClosedDatabase(const string16& origin_identifier, databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); origins_info_map_.erase(origin_identifier); - // Try to delete the origin in case this was the last database. std::vector<DatabaseDetails> details; if (databases_table_->GetAllDatabaseDetailsForOrigin( - origin_identifier, &details) && details.empty()) + origin_identifier, &details) && details.empty()) { + // Try to delete the origin in case this was the last database. DeleteOrigin(origin_identifier); + } else if (quota_manager_proxy_) { + // TODO(michaeln): notify the quota manager + // CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); + // if (origin_info) + // quota_manager_proxy_->NotifyStorageConsumed( + // quota::QuotaClient::kDatabase, + // DatabaseUtil::GetOriginFromIdentifier(origin_identifier), + // quota::kStorageTypeTemporary, + // origin_info->TotalSize()); + } return true; } @@ -340,6 +392,16 @@ bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { return false; databases_table_->DeleteOrigin(origin_identifier); + + if (quota_manager_proxy_) { + // TODO(michaeln): notify the quota manager + // quota_manager_proxy_->NotifyStorageConsumed( + // quota::QuotaClient::kDatabase, + // DatabaseUtil::GetOriginFromIdentifier(origin_identifier), + // quota::kStorageTypeTemporary, + // 0); + } + return true; } @@ -488,6 +550,7 @@ int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, int64 DatabaseTracker::GetOriginSpaceAvailable( const string16& origin_identifier) { + // TODO(michaeln): Come up with a value according to the the QuotaMgr. CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); if (!origin_info) return 0; @@ -687,6 +750,7 @@ void DatabaseTracker::DeleteIncognitoDBDirectory() { // static void DatabaseTracker::ClearLocalState(const FilePath& profile_path) { + // TODO(michaeln): use SpecialStoragePolicy instead of kExtensionOriginPrefix FilePath db_dir = profile_path.Append(FilePath(kDatabaseDirectoryName)); FilePath db_tracker = db_dir.Append(FilePath(kTrackerDatabaseFileName)); if (file_util::DirectoryExists(db_dir) && diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h index 69130a5..2246a13 100644 --- a/webkit/database/database_tracker.h +++ b/webkit/database/database_tracker.h @@ -20,12 +20,17 @@ #include "net/base/completion_callback.h" #include "webkit/database/database_connections.h" +namespace base { +class MessageLoopProxy; +} + namespace sql { class Connection; class MetaTable; } namespace quota { +class QuotaManagerProxy; class SpecialStoragePolicy; } @@ -40,6 +45,7 @@ class QuotaTable; // This class is used to store information about all databases in an origin. class OriginInfo { public: + OriginInfo(); OriginInfo(const OriginInfo& origin_info); ~OriginInfo(); @@ -88,7 +94,9 @@ class DatabaseTracker }; DatabaseTracker(const FilePath& profile_path, bool is_incognito, - quota::SpecialStoragePolicy* special_storage_policy); + quota::SpecialStoragePolicy* special_storage_policy, + quota::QuotaManagerProxy* quota_manager_proxy, + base::MessageLoopProxy* db_tracker_thread); void DatabaseOpened(const string16& origin_identifier, const string16& database_name, @@ -111,9 +119,12 @@ class DatabaseTracker FilePath GetFullDBFilePath(const string16& origin_identifier, const string16& database_name); - bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info); - void SetOriginQuota(const string16& origin_identifier, int64 new_quota); + // virtual for unittesting only + virtual bool GetOriginInfo(const string16& origin_id, OriginInfo* info); + virtual bool GetAllOriginIdentifiers(std::vector<string16>* origin_ids); + virtual bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info); + void SetOriginQuota(const string16& origin_identifier, int64 new_quota); int64 GetDefaultQuota() { return default_quota_; } // Sets the default quota for all origins. Should be used in tests only. void SetDefaultQuota(int64 quota); @@ -158,8 +169,8 @@ class DatabaseTracker static void ClearLocalState(const FilePath& profile_path); private: - // Need this here to allow RefCountedThreadSafe to call ~DatabaseTracker(). friend class base::RefCountedThreadSafe<DatabaseTracker>; + friend class MockDatabaseTracker; // for testing typedef std::map<string16, std::set<string16> > DatabaseSet; typedef std::map<net::CompletionCallback*, DatabaseSet> PendingCompletionMap; @@ -185,7 +196,8 @@ class DatabaseTracker } }; - ~DatabaseTracker(); + // virtual for unittesting only + virtual ~DatabaseTracker(); bool DeleteClosedDatabase(const string16& origin_identifier, const string16& database_name); @@ -243,6 +255,8 @@ class DatabaseTracker // Apps and Extensions can have special rights. scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; + scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; + // When in incognito mode, store a DELETE_ON_CLOSE handle to each // main DB and journal file that was accessed. When the incognito profile // goes away (or when the browser crashes), all these handles will be diff --git a/webkit/database/database_tracker_unittest.cc b/webkit/database/database_tracker_unittest.cc index 4ba3a54..66469bf 100644 --- a/webkit/database/database_tracker_unittest.cc +++ b/webkit/database/database_tracker_unittest.cc @@ -106,7 +106,8 @@ class DatabaseTracker_TestHelper_Test { ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr<DatabaseTracker> tracker( new DatabaseTracker(temp_dir.path(), incognito_mode, - new TestSpecialStoragePolicy)); + new TestSpecialStoragePolicy, + NULL, NULL)); // Create and open three databases. int64 database_size = 0; @@ -209,7 +210,8 @@ class DatabaseTracker_TestHelper_Test { ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr<DatabaseTracker> tracker( new DatabaseTracker(temp_dir.path(), incognito_mode, - new TestSpecialStoragePolicy)); + new TestSpecialStoragePolicy, + NULL, NULL)); // Add two observers. TestObserver observer1; diff --git a/webkit/database/webkit_database.gypi b/webkit/database/webkit_database.gypi index 83ecf6b..11c30f5 100644 --- a/webkit/database/webkit_database.gypi +++ b/webkit/database/webkit_database.gypi @@ -12,12 +12,15 @@ '<(DEPTH)/app/app.gyp:app_base', '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/third_party/sqlite/sqlite.gyp:sqlite', + '<(DEPTH)/webkit/support/webkit_support.gyp:quota', ], 'sources': [ 'databases_table.cc', 'databases_table.h', 'database_connections.cc', 'database_connections.h', + 'database_quota_client.cc', + 'database_quota_client.h', 'database_tracker.cc', 'database_tracker.h', 'database_util.cc', diff --git a/webkit/support/simple_database_system.cc b/webkit/support/simple_database_system.cc index 62bd03e..a2f37ad 100644 --- a/webkit/support/simple_database_system.cc +++ b/webkit/support/simple_database_system.cc @@ -34,7 +34,7 @@ SimpleDatabaseSystem::SimpleDatabaseSystem() DCHECK(!instance_); instance_ = this; CHECK(temp_dir_.CreateUniqueTempDir()); - db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL); + db_tracker_ = new DatabaseTracker(temp_dir_.path(), false, NULL, NULL, NULL); db_tracker_->AddObserver(this); db_thread_.Start(); db_thread_proxy_ = db_thread_.message_loop_proxy(); diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index 699901e..d289200 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -372,6 +372,7 @@ '../../blob/blob_url_request_job_unittest.cc', '../../blob/deletable_file_reference_unittest.cc', '../../database/database_connections_unittest.cc', + '../../database/database_quota_client_unittest.cc', '../../database/databases_table_unittest.cc', '../../database/database_tracker_unittest.cc', '../../database/database_util_unittest.cc', |