diff options
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.cc | 29 | ||||
-rw-r--r-- | chrome/browser/renderer_host/database_dispatcher_host.h | 7 | ||||
-rw-r--r-- | webkit/database/database_connections.cc | 78 | ||||
-rw-r--r-- | webkit/database/database_connections.h | 41 | ||||
-rw-r--r-- | webkit/database/database_tracker.cc | 176 | ||||
-rw-r--r-- | webkit/database/database_tracker.h | 84 | ||||
-rw-r--r-- | webkit/database/database_tracker_unittest.cc | 123 | ||||
-rw-r--r-- | webkit/database/databases_table.cc | 25 | ||||
-rw-r--r-- | webkit/database/databases_table.h | 2 | ||||
-rw-r--r-- | webkit/database/databases_table_unittest.cc | 28 | ||||
-rw-r--r-- | webkit/database/quota_table.cc | 63 | ||||
-rw-r--r-- | webkit/database/quota_table.h | 33 | ||||
-rw-r--r-- | webkit/database/quota_table_unittest.cc | 65 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_database_system.cc | 14 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_database_system.h | 3 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gyp | 1 | ||||
-rw-r--r-- | webkit/webkit.gyp | 4 |
17 files changed, 658 insertions, 118 deletions
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc index 41b8331..c79796a 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.cc +++ b/chrome/browser/renderer_host/database_dispatcher_host.cc @@ -67,6 +67,12 @@ void DatabaseDispatcherHost::AddObserver() { void DatabaseDispatcherHost::RemoveObserver() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + + // If the renderer process died without closing all databases, + // then we need to manually close those connections + db_tracker_->CloseDatabases(database_connections_); + database_connections_.RemoveAllConnections(); + db_tracker_->RemoveObserver(this); } @@ -305,7 +311,7 @@ void DatabaseDispatcherHost::DatabaseOpened(const string16& origin_identifier, DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); int64 database_size = 0; int64 space_available = 0; - AddAccessedOrigin(origin_identifier); + database_connections_.AddConnection(origin_identifier, database_name); db_tracker_->DatabaseOpened(origin_identifier, database_name, description, estimated_size, &database_size, &space_available); ChromeThread::PostTask( @@ -331,7 +337,8 @@ void DatabaseDispatcherHost::OnDatabaseModified( void DatabaseDispatcherHost::DatabaseModified(const string16& origin_identifier, const string16& database_name) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - if (!HasAccessedOrigin(origin_identifier)) { + if (!database_connections_.IsDatabaseOpened( + origin_identifier, database_name)) { ReceivedBadMessage(ViewHostMsg_DatabaseModified::ID); return; } @@ -352,12 +359,14 @@ void DatabaseDispatcherHost::OnDatabaseClosed(const string16& origin_identifier, void DatabaseDispatcherHost::DatabaseClosed(const string16& origin_identifier, const string16& database_name) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - if (!HasAccessedOrigin(origin_identifier)) { + if (!database_connections_.IsDatabaseOpened( + origin_identifier, database_name)) { ReceivedBadMessage(ViewHostMsg_DatabaseClosed::ID); return; } db_tracker_->DatabaseClosed(origin_identifier, database_name); + database_connections_.RemoveConnection(origin_identifier, database_name); } void DatabaseDispatcherHost::OnDatabaseSizeChanged( @@ -366,7 +375,7 @@ void DatabaseDispatcherHost::OnDatabaseSizeChanged( int64 database_size, int64 space_available) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - if (HasAccessedOrigin(origin_identifier)) { + if (database_connections_.IsOriginUsed(origin_identifier)) { ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(this, @@ -376,15 +385,3 @@ void DatabaseDispatcherHost::OnDatabaseSizeChanged( database_size, space_available))); } } - -void DatabaseDispatcherHost::AddAccessedOrigin( - const string16& origin_identifier) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - accessed_origins_.insert(origin_identifier); -} - -bool DatabaseDispatcherHost::HasAccessedOrigin( - const string16& origin_identifier) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); - return (accessed_origins_.find(origin_identifier) != accessed_origins_.end()); -} diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h index eb0f8f1..301c261 100644 --- a/chrome/browser/renderer_host/database_dispatcher_host.h +++ b/chrome/browser/renderer_host/database_dispatcher_host.h @@ -10,6 +10,7 @@ #include "base/ref_counted.h" #include "base/string16.h" #include "ipc/ipc_message.h" +#include "webkit/database/database_connections.h" #include "webkit/database/database_tracker.h" class DatabaseDispatcherHost @@ -81,9 +82,6 @@ class DatabaseDispatcherHost void DatabaseClosed(const string16& origin_identifier, const string16& database_name); - void AddAccessedOrigin(const string16& origin_identifier); - bool HasAccessedOrigin(const string16& origin_identifier); - // The database tracker for the current profile. scoped_refptr<webkit_database::DatabaseTracker> db_tracker_; @@ -102,7 +100,8 @@ class DatabaseDispatcherHost // only when the corresponding renderer process is about to go away. bool shutdown_; - base::hash_set<string16> accessed_origins_; + // Keeps track of all DB connections opened by this renderer + webkit_database::DatabaseConnections database_connections_; }; #endif // CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_ diff --git a/webkit/database/database_connections.cc b/webkit/database/database_connections.cc new file mode 100644 index 0000000..a6e6d3d --- /dev/null +++ b/webkit/database/database_connections.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2009 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_connections.h" + +#include "base/logging.h" + +namespace webkit_database { + +DatabaseConnections::DatabaseConnections() { +} + +DatabaseConnections::~DatabaseConnections() { + DCHECK(connections_.empty()); +} + +bool DatabaseConnections::IsDatabaseOpened(const string16& origin_identifier, + const string16& database_name) { + OriginConnections::const_iterator origin_it = + connections_.find(origin_identifier); + if (origin_it == connections_.end()) + return false; + const DBConnections& origin_connections = origin_it->second; + return (origin_connections.find(database_name) != origin_connections.end()); +} + +bool DatabaseConnections::IsOriginUsed(const string16& origin_identifier) { + return (connections_.find(origin_identifier) != connections_.end()); +} + +void DatabaseConnections::AddConnection(const string16& origin_identifier, + const string16& database_name) { + connections_[origin_identifier][database_name]++; +} + +void DatabaseConnections::RemoveConnection(const string16& origin_identifier, + const string16& database_name) { + RemoveConnectionsHelper(origin_identifier, database_name, 1); +} + +void DatabaseConnections::RemoveAllConnections() { + connections_.clear(); +} + +void DatabaseConnections::RemoveConnections( + const DatabaseConnections& connections) { + for (OriginConnections::const_iterator origin_it = + connections.connections_.begin(); + origin_it != connections.connections_.end(); + origin_it++) { + const DBConnections& db_connections = origin_it->second; + for (DBConnections::const_iterator db_it = db_connections.begin(); + db_it != db_connections.end(); db_it++) { + RemoveConnectionsHelper(origin_it->first, db_it->first, db_it->second); + } + } +} + +void DatabaseConnections::RemoveConnectionsHelper( + const string16& origin_identifier, + const string16& database_name, + int num_connections) { + OriginConnections::iterator origin_iterator = + connections_.find(origin_identifier); + DCHECK(origin_iterator != connections_.end()); + DBConnections& db_connections = origin_iterator->second; + int& count = db_connections[database_name]; + DCHECK(count >= num_connections); + count -= num_connections; + if (!count) { + db_connections.erase(database_name); + if (db_connections.empty()) + connections_.erase(origin_iterator); + } +} + +} // namespace webkit_database diff --git a/webkit/database/database_connections.h b/webkit/database/database_connections.h new file mode 100644 index 0000000..e036940 --- /dev/null +++ b/webkit/database/database_connections.h @@ -0,0 +1,41 @@ +// Copyright (c) 2009 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_CONNECTIONS_H_ +#define WEBKIT_DATABASE_DATABASE_CONNECTIONS_H_ + +#include "base/string16.h" + +#include <map> + +namespace webkit_database { + +class DatabaseConnections { + public: + DatabaseConnections(); + ~DatabaseConnections(); + + bool IsDatabaseOpened(const string16& origin_identifier, + const string16& database_name); + bool IsOriginUsed(const string16& origin_identifier); + void AddConnection(const string16& origin_identifier, + const string16& database_name); + void RemoveConnection(const string16& origin_identifier, + const string16& database_name); + void RemoveAllConnections(); + void RemoveConnections(const DatabaseConnections& connections); + + private: + typedef std::map<string16, int> DBConnections; + typedef std::map<string16, DBConnections> OriginConnections; + OriginConnections connections_; + + void RemoveConnectionsHelper(const string16& origin_identifier, + const string16& database_name, + int num_connections); +}; + +} // namespace webkit_database + +#endif // WEBKIT_DATABASE_DATABASE_CONNECTIONS_H_ diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc index efece6d6..16766b4 100644 --- a/webkit/database/database_tracker.cc +++ b/webkit/database/database_tracker.cc @@ -9,11 +9,13 @@ #include "app/sql/connection.h" #include "app/sql/meta_table.h" #include "app/sql/statement.h" +#include "app/sql/transaction.h" #include "base/basictypes.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/string_util.h" #include "webkit/database/databases_table.h" +#include "webkit/database/quota_table.h" namespace webkit_database { @@ -21,7 +23,7 @@ const FilePath::CharType kDatabaseDirectoryName[] = FILE_PATH_LITERAL("databases"); const FilePath::CharType kTrackerDatabaseFileName[] = FILE_PATH_LITERAL("Databases.db"); -const int kCurrentVersion = 1; +const int kCurrentVersion = 2; const int kCompatibleVersion = 1; const int64 kDefaultQuota = 5 * 1024 * 1024; const int64 kDefaultExtensionQuota = 50 * 1024 * 1024; @@ -53,8 +55,10 @@ void DatabaseTracker::DatabaseOpened(const string16& origin_identifier, InsertOrUpdateDatabaseDetails(origin_identifier, database_name, database_description, estimated_size); + database_connections_.AddConnection(origin_identifier, database_name); - *database_size = GetCachedDatabaseFileSize(origin_identifier, database_name); + CachedOriginInfo* info = GetCachedOriginInfo(origin_identifier); + *database_size = (info ? info->GetDatabaseSize(database_name) : 0); *space_available = GetOriginSpaceAvailable(origin_identifier); } @@ -72,7 +76,11 @@ void DatabaseTracker::DatabaseModified(const string16& origin_identifier, void DatabaseTracker::DatabaseClosed(const string16& origin_identifier, const string16& database_name) { - // TODO(dumi): figure out how to use this information at a later time + database_connections_.RemoveConnection(origin_identifier, database_name); +} + +void DatabaseTracker::CloseDatabases(const DatabaseConnections& connections) { + database_connections_.RemoveConnections(connections); } void DatabaseTracker::AddObserver(Observer* observer) { @@ -91,6 +99,7 @@ void DatabaseTracker::CloseTrackerDatabaseAndClearCaches() { ClearAllCachedOriginInfo(); meta_table_.reset(NULL); databases_table_.reset(NULL); + quota_table_.reset(NULL); db_->Close(); initialized_ = false; } @@ -110,36 +119,101 @@ FilePath DatabaseTracker::GetFullDBFilePath( UTF16ToWide(origin_identifier))).Append(file_name); } +bool DatabaseTracker::GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) { + DCHECK(origins_info); + DCHECK(origins_info->empty()); + std::vector<string16> origins; + if (!databases_table_->GetAllOrigins(&origins)) + return false; + + for (std::vector<string16>::const_iterator it = origins.begin(); + it != origins.end(); it++) { + CachedOriginInfo* origin_info = GetCachedOriginInfo(*it); + if (!origin_info) { + // Restore 'origins_info' to its initial state. + origins_info->clear(); + return false; + } + origins_info->push_back(OriginInfo(*origin_info)); + } + + return true; +} + +void DatabaseTracker::SetOriginQuota(const string16& origin_identifier, + int64 new_quota) { + if (quota_table_->SetOriginQuota(origin_identifier, new_quota) && + (origins_info_map_.find(origin_identifier) != origins_info_map_.end())) { + origins_info_map_[origin_identifier].SetQuota(new_quota); + } +} + +bool DatabaseTracker::DeleteDatabase(const string16& origin_identifier, + const string16& database_name) { + // Check if the database is opened by any renderer. + if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) + return false; + + // Try to delete the file on the hard drive. + FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); + if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) + return false; + + // Clean up the main database and invalidate the cached record. + databases_table_->DeleteDatabaseDetails(origin_identifier, database_name); + origins_info_map_.erase(origin_identifier); + return true; +} + +bool DatabaseTracker::DeleteOrigin(const string16& origin_identifier) { + // Check if any database in this origin is opened by any renderer. + if (database_connections_.IsOriginUsed(origin_identifier)) + return false; + + // We need to invalidate the cached record whether file_util::Delete() + // succeeds or not, because even if it fails, it might still delete some + // DB files on the hard drive. + origins_info_map_.erase(origin_identifier); + FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( + UTF16ToWide(origin_identifier))); + if (!file_util::Delete(origin_dir, true)) + return false; + + databases_table_->DeleteOrigin(origin_identifier); + return true; +} + bool DatabaseTracker::LazyInit() { if (!initialized_) { DCHECK(!db_->is_open()); DCHECK(!databases_table_.get()); + DCHECK(!quota_table_.get()); DCHECK(!meta_table_.get()); // If the tracker database exists, but it's corrupt or doesn't - // have a meta table, delete the database directory + // have a meta table, delete the database directory. const FilePath kTrackerDatabaseFullPath = db_dir_.Append(FilePath(kTrackerDatabaseFileName)); if (file_util::DirectoryExists(db_dir_) && file_util::PathExists(kTrackerDatabaseFullPath) && (!db_->Open(kTrackerDatabaseFullPath) || - !db_->DoesTableExist("meta"))) { + !sql::MetaTable::DoesTableExist(db_.get()))) { db_->Close(); if (!file_util::Delete(db_dir_, true)) return false; } databases_table_.reset(new DatabasesTable(db_.get())); + quota_table_.reset(new QuotaTable(db_.get())); meta_table_.reset(new sql::MetaTable()); initialized_ = file_util::CreateDirectory(db_dir_) && (db_->is_open() || db_->Open(kTrackerDatabaseFullPath)) && - meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) && - (meta_table_->GetCompatibleVersionNumber() <= kCurrentVersion) && - databases_table_->Init(); + UpgradeToCurrentVersion(); if (!initialized_) { databases_table_.reset(NULL); + quota_table_.reset(NULL); meta_table_.reset(NULL); db_->Close(); } @@ -147,6 +221,21 @@ bool DatabaseTracker::LazyInit() { return initialized_; } +bool DatabaseTracker::UpgradeToCurrentVersion() { + sql::Transaction transaction(db_.get()); + if (!transaction.Begin() || + !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) || + (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) || + !databases_table_->Init() || + !quota_table_->Init()) + return false; + + if (meta_table_->GetVersionNumber() < kCurrentVersion) + meta_table_->SetVersionNumber(kCurrentVersion); + + return transaction.Commit(); +} + void DatabaseTracker::InsertOrUpdateDatabaseDetails( const string16& origin_identifier, const string16& database_name, @@ -168,21 +257,15 @@ void DatabaseTracker::InsertOrUpdateDatabaseDetails( } } -int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, - const string16& database_name) const { - FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name); - int64 db_file_size = 0; - if (!file_util::GetFileSize(db_file_name, &db_file_size)) - db_file_size = 0; - return db_file_size; -} - void DatabaseTracker::ClearAllCachedOriginInfo() { origins_info_map_.clear(); } DatabaseTracker::CachedOriginInfo* DatabaseTracker::GetCachedOriginInfo( const string16& origin_identifier) { + if (!LazyInit()) + return NULL; + // Populate the cache with data for this origin if needed. if (origins_info_map_.find(origin_identifier) == origins_info_map_.end()) { std::vector<DatabaseDetails> details; @@ -192,24 +275,45 @@ DatabaseTracker::CachedOriginInfo* DatabaseTracker::GetCachedOriginInfo( } CachedOriginInfo& origin_info = origins_info_map_[origin_identifier]; + origin_info.SetOrigin(origin_identifier); for (std::vector<DatabaseDetails>::const_iterator it = details.begin(); it != details.end(); it++) { int64 db_file_size = - GetDBFileSize(it->origin_identifier, it->database_name); - origin_info.SetCachedDatabaseSize(it->database_name, db_file_size); + GetDBFileSize(origin_identifier, it->database_name); + origin_info.SetDatabaseSize(it->database_name, db_file_size); + } + + int64 origin_quota = quota_table_->GetOriginQuota(origin_identifier); + if (origin_quota > 0) { + origin_info.SetQuota(origin_quota); + } else if (StartsWith(origin_identifier, + ASCIIToUTF16(kExtensionOriginIdentifierPrefix), + true)) { + origin_info.SetQuota(kDefaultExtensionQuota); + } else { + origin_info.SetQuota(kDefaultQuota); } } return &origins_info_map_[origin_identifier]; } -int64 DatabaseTracker::GetCachedDatabaseFileSize( - const string16& origin_identifier, - const string16& database_name) { +int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, + const string16& database_name) const { + FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name); + int64 db_file_size = 0; + if (!file_util::GetFileSize(db_file_name, &db_file_size)) + db_file_size = 0; + return db_file_size; +} + +int64 DatabaseTracker::GetOriginSpaceAvailable( + const string16& origin_identifier) { CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); if (!origin_info) return 0; - return origin_info->GetCachedDatabaseSize(database_name); + int64 space_available = origin_info->Quota() - origin_info->TotalSize(); + return (space_available < 0 ? 0 : space_available); } int64 DatabaseTracker::UpdateCachedDatabaseFileSize( @@ -218,32 +322,8 @@ int64 DatabaseTracker::UpdateCachedDatabaseFileSize( int64 new_size = GetDBFileSize(origin_identifier, database_name); CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); if (origin_info) - origin_info->SetCachedDatabaseSize(database_name, new_size); + origin_info->SetDatabaseSize(database_name, new_size); return new_size; } -int64 DatabaseTracker::GetOriginUsage(const string16& origin_identifier) { - CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); - if (!origin_info) - return kint64max; - return origin_info->TotalSize(); -} - -int64 DatabaseTracker::GetOriginQuota( - const string16& origin_identifier) const { - if (StartsWith(origin_identifier, - ASCIIToUTF16(kExtensionOriginIdentifierPrefix), true)) { - return kDefaultExtensionQuota; - } - - return kDefaultQuota; -} - -int64 DatabaseTracker::GetOriginSpaceAvailable( - const string16& origin_identifier) { - int64 space_available = GetOriginQuota(origin_identifier) - - GetOriginUsage(origin_identifier); - return (space_available < 0 ? 0 : space_available); -} - } // namespace webkit_database diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h index 2bcfc6f..8d65109 100644 --- a/webkit/database/database_tracker.h +++ b/webkit/database/database_tracker.h @@ -12,7 +12,9 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/string16.h" +#include "base/string_util.h" #include "testing/gtest/include/gtest/gtest_prod.h" +#include "webkit/database/database_connections.h" namespace sql { class Connection; @@ -22,6 +24,42 @@ class MetaTable; namespace webkit_database { class DatabasesTable; +class QuotaTable; + +// This class is used to store information about all databases in an origin. +class OriginInfo { + public: + OriginInfo(const OriginInfo& origin_info) + : origin_(origin_info.origin_), + total_size_(origin_info.total_size_), + quota_(origin_info.quota_), + database_sizes_(origin_info.database_sizes_) {} + string16 GetOrigin() const { return origin_; } + int64 TotalSize() const { return total_size_; } + int64 Quota() const { return quota_; } + void GetAllDatabaseNames(std::vector<string16>* databases) const { + for (std::map<string16, int64>::const_iterator it = database_sizes_.begin(); + it != database_sizes_.end(); it++) { + databases->push_back(it->first); + } + } + int64 GetDatabaseSize(const string16& database_name) const { + std::map<string16, int64>::const_iterator it = + database_sizes_.find(database_name); + if (it != database_sizes_.end()) + return it->second; + return 0; + } + + protected: + OriginInfo(const string16& origin, int64 total_size, int64 quota) + : origin_(origin), total_size_(total_size), quota_(quota) { } + + string16 origin_; + int64 total_size_; + int64 quota_; + std::map<string16, int64> database_sizes_; +}; // This class manages the main database, and keeps track of per origin quotas. // @@ -58,6 +96,7 @@ class DatabaseTracker const string16& database_name); void DatabaseClosed(const string16& origin_identifier, const string16& database_name); + void CloseDatabases(const DatabaseConnections& connections); void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -68,31 +107,33 @@ class DatabaseTracker FilePath GetFullDBFilePath(const string16& origin_identifier, const string16& database_name) const; + bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info); + void SetOriginQuota(const string16& origin_identifier, int64 new_quota); + bool DeleteDatabase(const string16& origin_identifier, + const string16& database_name); + bool DeleteOrigin(const string16& origin_identifier); + private: + // Need this here to allow RefCountedThreadSafe to call ~DatabaseTracker(). friend class base::RefCountedThreadSafe<DatabaseTracker>; - ~DatabaseTracker(); - - class CachedOriginInfo { + class CachedOriginInfo : public OriginInfo { public: - CachedOriginInfo() : total_size_(0) { } - int64 TotalSize() const { return total_size_; } - int64 GetCachedDatabaseSize(const string16& database_name) { - return cached_database_sizes_[database_name]; - } - void SetCachedDatabaseSize(const string16& database_name, int64 new_size) { - int64 old_size = cached_database_sizes_[database_name]; - cached_database_sizes_[database_name] = new_size; + CachedOriginInfo() : OriginInfo(EmptyString16(), 0, 0) {} + void SetOrigin(const string16& origin) { origin_ = origin; } + void SetQuota(int64 new_quota) { quota_ = new_quota; } + void SetDatabaseSize(const string16& database_name, int64 new_size) { + int64 old_size = database_sizes_[database_name]; + database_sizes_[database_name] = new_size; if (new_size != old_size) total_size_ += new_size - old_size; } - - private: - int64 total_size_; - std::map<string16, int64> cached_database_sizes_; }; + ~DatabaseTracker(); + bool LazyInit(); + bool UpgradeToCurrentVersion(); void InsertOrUpdateDatabaseDetails(const string16& origin_identifier, const string16& database_name, const string16& database_details, @@ -100,23 +141,24 @@ class DatabaseTracker void ClearAllCachedOriginInfo(); CachedOriginInfo* GetCachedOriginInfo(const string16& origin_identifier); - int64 GetCachedDatabaseFileSize(const string16& origin_identifier, - const string16& database_name); - int64 UpdateCachedDatabaseFileSize(const string16& origin_identifier, - const string16& database_name); + int64 GetDBFileSize(const string16& origin_identifier, const string16& database_name) const; - int64 GetOriginUsage(const string16& origin_identifer); - int64 GetOriginQuota(const string16& origin_identifier) const; + int64 GetOriginSpaceAvailable(const string16& origin_identifier); + int64 UpdateCachedDatabaseFileSize(const string16& origin_identifier, + const string16& database_name); + bool initialized_; const FilePath db_dir_; scoped_ptr<sql::Connection> db_; scoped_ptr<DatabasesTable> databases_table_; + scoped_ptr<QuotaTable> quota_table_; scoped_ptr<sql::MetaTable> meta_table_; ObserverList<Observer> observers_; std::map<string16, CachedOriginInfo> origins_info_map_; + DatabaseConnections database_connections_; FRIEND_TEST(DatabaseTrackerTest, TestIt); }; diff --git a/webkit/database/database_tracker_unittest.cc b/webkit/database/database_tracker_unittest.cc index cf9fb5d..8b44a451 100644 --- a/webkit/database/database_tracker_unittest.cc +++ b/webkit/database/database_tracker_unittest.cc @@ -70,9 +70,6 @@ TEST(DatabaseTrackerTest, TestIt) { EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); scoped_refptr<DatabaseTracker> tracker(new DatabaseTracker(temp_dir.path())); - // Get the default quota for all origins. - const int64 kDefaultQuota = tracker->GetOriginQuota(EmptyString16()); - // Add two observers. TestObserver observer1; TestObserver observer2; @@ -89,24 +86,43 @@ TEST(DatabaseTrackerTest, TestIt) { const string16 kDB3 = ASCIIToUTF16("db3"); const string16 kDescription = ASCIIToUTF16("database_description"); + // Get the quota for kOrigin1 and kOrigin2 + DatabaseTracker::CachedOriginInfo* origin1_info = + tracker->GetCachedOriginInfo(kOrigin1); + DatabaseTracker::CachedOriginInfo* origin2_info = + tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_TRUE(origin2_info); + int64 origin1_quota = origin1_info->Quota(); + int64 origin2_quota = origin2_info->Quota(); + EXPECT_EQ(origin1_quota, tracker->GetOriginSpaceAvailable(kOrigin1)); + EXPECT_EQ(origin2_quota, tracker->GetOriginSpaceAvailable(kOrigin2)); + + // Set a new quota for kOrigin1 + origin1_quota *= 2; + tracker->SetOriginQuota(kOrigin1, origin1_quota); + origin1_info = tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_EQ(origin1_quota, origin1_info->Quota()); + tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, &database_size, &space_available); EXPECT_EQ(0, database_size); - EXPECT_EQ(kDefaultQuota, space_available); + EXPECT_EQ(origin1_quota, space_available); tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, &database_size, &space_available); EXPECT_EQ(0, database_size); - EXPECT_EQ(kDefaultQuota, space_available); + EXPECT_EQ(origin2_quota, space_available); tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0, &database_size, &space_available); EXPECT_EQ(0, database_size); - EXPECT_EQ(kDefaultQuota, space_available); + EXPECT_EQ(origin1_quota, space_available); // Tell the tracker that a database has changed. // Even though nothing has changed, the observers should be notified. tracker->DatabaseModified(kOrigin1, kDB1); - CheckNotificationReceived(&observer1, kOrigin1, kDB1, 0, kDefaultQuota); - CheckNotificationReceived(&observer2, kOrigin1, kDB1, 0, kDefaultQuota); + CheckNotificationReceived(&observer1, kOrigin1, kDB1, 0, origin1_quota); + CheckNotificationReceived(&observer2, kOrigin1, kDB1, 0, origin1_quota); // Write some data to each file and check that the listeners are // called with the appropriate values. @@ -121,28 +137,38 @@ TEST(DatabaseTrackerTest, TestIt) { EXPECT_EQ(4, file_util::WriteFile( tracker->GetFullDBFilePath(kOrigin1, kDB3), "aaaa", 4)); tracker->DatabaseModified(kOrigin1, kDB1); - CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1, kDefaultQuota - 1); - CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1, kDefaultQuota - 1); + CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1, origin1_quota - 1); + CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1, origin1_quota - 1); tracker->DatabaseModified(kOrigin2, kDB2); - CheckNotificationReceived(&observer1, kOrigin2, kDB2, 2, kDefaultQuota - 2); - CheckNotificationReceived(&observer2, kOrigin2, kDB2, 2, kDefaultQuota - 2); + CheckNotificationReceived(&observer1, kOrigin2, kDB2, 2, origin2_quota - 2); + CheckNotificationReceived(&observer2, kOrigin2, kDB2, 2, origin2_quota - 2); tracker->DatabaseModified(kOrigin1, kDB3); - CheckNotificationReceived(&observer1, kOrigin1, kDB3, 4, kDefaultQuota - 5); - CheckNotificationReceived(&observer2, kOrigin1, kDB3, 4, kDefaultQuota - 5); + CheckNotificationReceived(&observer1, kOrigin1, kDB3, 4, origin1_quota - 5); + CheckNotificationReceived(&observer2, kOrigin1, kDB3, 4, origin1_quota - 5); + + // Make sure the available space for kOrigin1 and kOrigin2 changed accordingly + EXPECT_EQ(origin1_quota - 5, tracker->GetOriginSpaceAvailable(kOrigin1)); + EXPECT_EQ(origin2_quota - 2, tracker->GetOriginSpaceAvailable(kOrigin2)); + + // Close all databases + tracker->DatabaseClosed(kOrigin1, kDB1); + tracker->DatabaseClosed(kOrigin2, kDB2); + tracker->DatabaseClosed(kOrigin1, kDB3); // Open an existing database and check the reported size tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, &database_size, &space_available); EXPECT_EQ(1, database_size); - EXPECT_EQ(kDefaultQuota - 5, space_available); + EXPECT_EQ(origin1_quota - 5, space_available); // Make sure that the observers are notified even if // the size of the database hasn't changed. EXPECT_EQ(1, file_util::WriteFile( tracker->GetFullDBFilePath(kOrigin1, kDB1), "b", 1)); tracker->DatabaseModified(kOrigin1, kDB1); - CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1, kDefaultQuota - 5); - CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1, kDefaultQuota - 5); + CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1, origin1_quota - 5); + CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1, origin1_quota - 5); + tracker->DatabaseClosed(kOrigin1, kDB1); // Remove an observer; this should clear all caches. tracker->RemoveObserver(&observer2); @@ -156,8 +182,9 @@ TEST(DatabaseTrackerTest, TestIt) { EXPECT_EQ(6, file_util::WriteFile( tracker->GetFullDBFilePath(kOrigin1, kDB3), "dddddd", 6)); tracker->DatabaseModified(kOrigin1, kDB1); - CheckNotificationReceived(&observer1, kOrigin1, kDB1, 5, kDefaultQuota - 11); + CheckNotificationReceived(&observer1, kOrigin1, kDB1, 5, origin1_quota - 11); EXPECT_FALSE(observer2.DidReceiveNewNotification()); + EXPECT_EQ(origin1_quota - 11, tracker->GetOriginSpaceAvailable(kOrigin1)); // Close the tracker database and clear all caches. // Then make sure that DatabaseOpened() still returns the correct result. @@ -165,16 +192,70 @@ TEST(DatabaseTrackerTest, TestIt) { tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, &database_size, &space_available); EXPECT_EQ(5, database_size); - EXPECT_EQ(kDefaultQuota - 11, space_available); + EXPECT_EQ(origin1_quota - 11, space_available); // Close the tracker database and clear all caches. Then make sure that // DatabaseModified() still calls the observers with correct values. tracker->CloseTrackerDatabaseAndClearCaches(); tracker->DatabaseModified(kOrigin1, kDB3); - CheckNotificationReceived(&observer1, kOrigin1, kDB3, 6, kDefaultQuota - 11); + CheckNotificationReceived(&observer1, kOrigin1, kDB3, 6, origin1_quota - 11); + tracker->DatabaseClosed(kOrigin1, kDB1); - // Clean up. + // Remove all observers. tracker->RemoveObserver(&observer1); + + // Trying to delete a database in use should fail + tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0, + &database_size, &space_available); + EXPECT_FALSE(tracker->DeleteDatabase(kOrigin1, kDB3)); + origin1_info = tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_EQ(6, origin1_info->GetDatabaseSize(kDB3)); + tracker->DatabaseClosed(kOrigin1, kDB3); + + // Delete a database and make sure the space used by that origin is updated + EXPECT_TRUE(tracker->DeleteDatabase(kOrigin1, kDB3)); + origin1_info = tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_EQ(origin1_quota - 5, tracker->GetOriginSpaceAvailable(kOrigin1)); + EXPECT_EQ(5, origin1_info->GetDatabaseSize(kDB1)); + EXPECT_EQ(0, origin1_info->GetDatabaseSize(kDB3)); + + // Get all data for all origins + std::vector<OriginInfo> origins_info; + EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); + EXPECT_EQ(size_t(2), origins_info.size()); + EXPECT_EQ(kOrigin1, origins_info[0].GetOrigin()); + EXPECT_EQ(5, origins_info[0].TotalSize()); + EXPECT_EQ(origin1_quota, origins_info[0].Quota()); + EXPECT_EQ(5, origins_info[0].GetDatabaseSize(kDB1)); + EXPECT_EQ(0, origins_info[0].GetDatabaseSize(kDB3)); + + EXPECT_EQ(kOrigin2, origins_info[1].GetOrigin()); + EXPECT_EQ(2, origins_info[1].TotalSize()); + EXPECT_EQ(origin2_quota, origins_info[1].Quota()); + + // Trying to delete an origin with databases in use should fail + tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, + &database_size, &space_available); + EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1)); + origin1_info = tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_EQ(5, origin1_info->GetDatabaseSize(kDB1)); + tracker->DatabaseClosed(kOrigin1, kDB1); + + // Delete an origin that doesn't have any database in use + EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1)); + origins_info.clear(); + EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); + EXPECT_EQ(size_t(1), origins_info.size()); + EXPECT_EQ(kOrigin2, origins_info[0].GetOrigin()); + + origin1_info = tracker->GetCachedOriginInfo(kOrigin1); + EXPECT_TRUE(origin1_info); + EXPECT_EQ(origin1_quota, origin1_info->Quota()); + EXPECT_EQ(0, origin1_info->TotalSize()); + EXPECT_EQ(origin1_quota, tracker->GetOriginSpaceAvailable(kOrigin1)); } } // namespace webkit_database diff --git a/webkit/database/databases_table.cc b/webkit/database/databases_table.cc index 132e7ad..a987522 100644 --- a/webkit/database/databases_table.cc +++ b/webkit/database/databases_table.cc @@ -112,12 +112,24 @@ bool DatabasesTable::DeleteDatabaseDetails(const string16& origin_identifier, return false; } +bool DatabasesTable::GetAllOrigins(std::vector<string16>* origins) { + sql::Statement statement(db_->GetCachedStatement( + SQL_FROM_HERE, "SELECT DISTINCT origin FROM Databases ORDER BY origin")); + if (statement.is_valid()) { + while (statement.Step()) + origins->push_back(UTF8ToUTF16(statement.ColumnString(0))); + return statement.Succeeded(); + } + + return false; +} + bool DatabasesTable::GetAllDatabaseDetailsForOrigin( const string16& origin_identifier, std::vector<DatabaseDetails>* details_vector) { sql::Statement statement(db_->GetCachedStatement( SQL_FROM_HERE, "SELECT name, description, estimated_size " - "FROM Databases WHERE origin = ? ORDER BY origin, name")); + "FROM Databases WHERE origin = ? ORDER BY name")); if (statement.is_valid() && statement.BindString(0, UTF16ToUTF8(origin_identifier))) { while (statement.Step()) { @@ -134,4 +146,15 @@ bool DatabasesTable::GetAllDatabaseDetailsForOrigin( return false; } +bool DatabasesTable::DeleteOrigin(const string16& origin_identifier) { + sql::Statement delete_statement(db_->GetCachedStatement( + SQL_FROM_HERE, "DELETE FROM Databases WHERE origin = ?")); + if (delete_statement.is_valid() && + delete_statement.BindString(0, UTF16ToUTF8(origin_identifier))) { + return (delete_statement.Run() && db_->GetLastChangeCount()); + } + + return false; +} + } // namespace webkit_database diff --git a/webkit/database/databases_table.h b/webkit/database/databases_table.h index 481489f..4443c76 100644 --- a/webkit/database/databases_table.h +++ b/webkit/database/databases_table.h @@ -38,8 +38,10 @@ class DatabasesTable { bool UpdateDatabaseDetails(const DatabaseDetails& details); bool DeleteDatabaseDetails(const string16& origin_identifier, const string16& database_name); + bool GetAllOrigins(std::vector<string16>* origins); bool GetAllDatabaseDetailsForOrigin(const string16& origin_identifier, std::vector<DatabaseDetails>* details); + bool DeleteOrigin(const string16& origin_identifier); private: sql::Connection* db_; }; diff --git a/webkit/database/databases_table_unittest.cc b/webkit/database/databases_table_unittest.cc index fb46d08..2d72d60 100644 --- a/webkit/database/databases_table_unittest.cc +++ b/webkit/database/databases_table_unittest.cc @@ -4,12 +4,11 @@ #include "app/sql/connection.h" #include "app/sql/statement.h" -#include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/database/databases_table.h" -namespace webkit_database { +namespace { class TestErrorDelegate : public sql::ErrorDelegate { public: @@ -20,6 +19,10 @@ class TestErrorDelegate : public sql::ErrorDelegate { } }; +} // namespace + +namespace webkit_database { + static void CheckDetailsAreEqual(const DatabaseDetails& d1, const DatabaseDetails& d2) { EXPECT_EQ(d1.origin_identifier, d2.origin_identifier); @@ -36,7 +39,6 @@ static bool DatabasesTableIsEmpty(sql::Connection* db) { TEST(DatabasesTableTest, TestIt) { // Initialize the 'Databases' table. - ScopedTempDir temp_dir; sql::Connection db; // Set an error delegate that will make all operations return false on error. @@ -44,8 +46,7 @@ TEST(DatabasesTableTest, TestIt) { db.set_error_delegate(error_delegate); // Initialize the temp dir and the 'Databases' table. - EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); - EXPECT_TRUE(db.Open(temp_dir.path().Append(FILE_PATH_LITERAL("tracker.db")))); + EXPECT_TRUE(db.OpenInMemory()); DatabasesTable databases_table(&db); EXPECT_TRUE(databases_table.Init()); @@ -116,6 +117,23 @@ TEST(DatabasesTableTest, TestIt) { CheckDetailsAreEqual(details_in1, details_out_origin1[0]); CheckDetailsAreEqual(details_in2, details_out_origin1[1]); + // Get the list of all origins: should be "origin1" and "origin2". + std::vector<string16> origins_out; + EXPECT_TRUE(databases_table.GetAllOrigins(&origins_out)); + EXPECT_EQ(size_t(2), origins_out.size()); + EXPECT_EQ(details_in1.origin_identifier, origins_out[0]); + EXPECT_EQ(details_in3.origin_identifier, origins_out[1]); + + // Delete an origin and check that it's no longer in the table. + origins_out.clear(); + EXPECT_TRUE(databases_table.DeleteOrigin(details_in3.origin_identifier)); + EXPECT_TRUE(databases_table.GetAllOrigins(&origins_out)); + EXPECT_EQ(size_t(1), origins_out.size()); + EXPECT_EQ(details_in1.origin_identifier, origins_out[0]); + + // Deleting an origin that doesn't have any record in this table should fail. + EXPECT_FALSE(databases_table.DeleteOrigin(ASCIIToUTF16("unknown_origin"))); + // Delete the details for 'db1' and check that they're no longer there. EXPECT_TRUE(databases_table.DeleteDatabaseDetails( details_in1.origin_identifier, details_in1.database_name)); diff --git a/webkit/database/quota_table.cc b/webkit/database/quota_table.cc new file mode 100644 index 0000000..2b6507e --- /dev/null +++ b/webkit/database/quota_table.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2009 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/quota_table.h" + +#include "app/sql/connection.h" +#include "app/sql/statement.h" +#include "base/string_util.h" + +namespace webkit_database { + +bool QuotaTable::Init() { + // 'Quota' schema: + // origin The origin. + // quota The quota for this origin. + return db_->DoesTableExist("Quota") || + db_->Execute( + "CREATE TABLE Quota (" + "origin TEXT NOT NULL PRIMARY KEY, " + "quota INTEGER NOT NULL)"); +} + +int64 QuotaTable::GetOriginQuota(const string16& origin_identifier) { + sql::Statement statement(db_->GetCachedStatement( + SQL_FROM_HERE, "SELECT quota FROM Quota WHERE origin = ?")); + if (statement.is_valid() && + statement.BindString(0, UTF16ToUTF8(origin_identifier)) && + statement.Step()) { + return statement.ColumnInt64(0); + } + + return -1; +} + +bool QuotaTable::SetOriginQuota(const string16& origin_identifier, + int64 quota) { + DCHECK(quota >= 0); + + // Insert or update the quota for this origin. + sql::Statement replace_statement(db_->GetCachedStatement( + SQL_FROM_HERE, "REPLACE INTO Quota VALUES (?, ?)")); + if (replace_statement.is_valid() && + replace_statement.BindString(0, UTF16ToUTF8(origin_identifier)) && + replace_statement.BindInt64(1, quota)) { + return replace_statement.Run(); + } + + return false; +} + +bool QuotaTable::ClearOriginQuota(const string16& origin_identifier) { + sql::Statement statement(db_->GetCachedStatement( + SQL_FROM_HERE, "DELETE FROM Quota WHERE origin = ?")); + if (statement.is_valid() && + statement.BindString(0, UTF16ToUTF8(origin_identifier))) { + return (statement.Run() && db_->GetLastChangeCount()); + } + + return false; +} + +} // namespace webkit_database diff --git a/webkit/database/quota_table.h b/webkit/database/quota_table.h new file mode 100644 index 0000000..8f6e4e8 --- /dev/null +++ b/webkit/database/quota_table.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009 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_QUOTA_TABLE_H_ +#define WEBKIT_DATABASE_QUOTA_TABLE_H_ + +#include <vector> + +#include "base/string16.h" + +namespace sql { +class Connection; +} + +namespace webkit_database { + +class QuotaTable { + public: + explicit QuotaTable(sql::Connection* db) : db_(db) { } + + bool Init(); + int64 GetOriginQuota(const string16& origin_identifier); + bool SetOriginQuota(const string16& origin_identifier, int64 quota); + bool ClearOriginQuota(const string16& origin_identifier); + + private: + sql::Connection* db_; +}; + +} // namespace webkit_database + +#endif // WEBKIT_DATABASE_QUOTA_TABLE_H_ diff --git a/webkit/database/quota_table_unittest.cc b/webkit/database/quota_table_unittest.cc new file mode 100644 index 0000000..fbb59bf --- /dev/null +++ b/webkit/database/quota_table_unittest.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2009 The Chromium Authos. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "app/sql/connection.h" +#include "app/sql/statement.h" +#include "base/string_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/database/quota_table.h" + +namespace { + +class TestErrorDelegate : public sql::ErrorDelegate { + public: + virtual ~TestErrorDelegate() { } + virtual int OnError( + int error, sql::Connection* connection, sql::Statement* stmt) { + return error; + } +}; + +} // namespace + +namespace webkit_database { + +static bool QuotaTableIsEmpty(sql::Connection* db) { + sql::Statement statement(db->GetCachedStatement( + SQL_FROM_HERE, "SELECT COUNT(*) FROM Quota")); + return (statement.is_valid() && statement.Step() && !statement.ColumnInt(0)); +} + +TEST(QuotaTableTest, TestIt) { + // Initialize the 'Quota' table. + sql::Connection db; + + // Set an error delegate that will make all operations return false on error. + scoped_refptr<TestErrorDelegate> error_delegate(new TestErrorDelegate()); + db.set_error_delegate(error_delegate); + + // Initialize the temp dir and the 'Databases' table. + EXPECT_TRUE(db.OpenInMemory()); + QuotaTable quota_table(&db); + EXPECT_TRUE(quota_table.Init()); + + // The 'Quota' table should be empty. + EXPECT_TRUE(QuotaTableIsEmpty(&db)); + + // Set and check the quota for a new origin. + string16 origin = ASCIIToUTF16("origin"); + EXPECT_TRUE(quota_table.SetOriginQuota(origin, 1000)); + EXPECT_EQ(1000, quota_table.GetOriginQuota(origin)); + + // Reset and check the quota for the same origin. + EXPECT_TRUE(quota_table.SetOriginQuota(origin, 2000)); + EXPECT_EQ(2000, quota_table.GetOriginQuota(origin)); + + // Clear the quota for an origin + EXPECT_TRUE(quota_table.ClearOriginQuota(origin)); + EXPECT_TRUE(quota_table.GetOriginQuota(origin) < 0); + + // Check that there's no quota set for unknown origins. + EXPECT_TRUE(quota_table.GetOriginQuota(ASCIIToUTF16("unknown_origin")) < 0); +} + +} // namespace webkit_database diff --git a/webkit/tools/test_shell/simple_database_system.cc b/webkit/tools/test_shell/simple_database_system.cc index 4bab033..2b9afe3 100644 --- a/webkit/tools/test_shell/simple_database_system.cc +++ b/webkit/tools/test_shell/simple_database_system.cc @@ -91,6 +91,7 @@ void SimpleDatabaseSystem::DatabaseOpened(const string16& origin_identifier, int64 estimated_size) { int64 database_size = 0; int64 space_available = 0; + database_connections_.AddConnection(origin_identifier, database_name); db_tracker_->DatabaseOpened(origin_identifier, database_name, description, estimated_size, &database_size, &space_available); SetFullFilePathsForVfsFile(origin_identifier, database_name); @@ -101,12 +102,17 @@ void SimpleDatabaseSystem::DatabaseOpened(const string16& origin_identifier, void SimpleDatabaseSystem::DatabaseModified(const string16& origin_identifier, const string16& database_name) { + DCHECK(database_connections_.IsDatabaseOpened( + origin_identifier, database_name)); db_tracker_->DatabaseModified(origin_identifier, database_name); } void SimpleDatabaseSystem::DatabaseClosed(const string16& origin_identifier, const string16& database_name) { + DCHECK(database_connections_.IsDatabaseOpened( + origin_identifier, database_name)); db_tracker_->DatabaseClosed(origin_identifier, database_name); + database_connections_.RemoveConnection(origin_identifier, database_name); } void SimpleDatabaseSystem::OnDatabaseSizeChanged( @@ -114,8 +120,10 @@ void SimpleDatabaseSystem::OnDatabaseSizeChanged( const string16& database_name, int64 database_size, int64 space_available) { - WebKit::WebDatabase::updateDatabaseSize( - origin_identifier, database_name, database_size, space_available); + if (database_connections_.IsOriginUsed(origin_identifier)) { + WebKit::WebDatabase::updateDatabaseSize( + origin_identifier, database_name, database_size, space_available); + } } void SimpleDatabaseSystem::databaseOpened(const WebKit::WebDatabase& database) { @@ -136,6 +144,8 @@ void SimpleDatabaseSystem::databaseClosed(const WebKit::WebDatabase& database) { } void SimpleDatabaseSystem::ClearAllDatabases() { + db_tracker_->CloseDatabases(database_connections_); + database_connections_.RemoveAllConnections(); db_tracker_->CloseTrackerDatabaseAndClearCaches(); file_util::Delete(db_tracker_->DatabaseDirectory(), true); file_names_.clear(); diff --git a/webkit/tools/test_shell/simple_database_system.h b/webkit/tools/test_shell/simple_database_system.h index 689bb43..ff92b3f 100644 --- a/webkit/tools/test_shell/simple_database_system.h +++ b/webkit/tools/test_shell/simple_database_system.h @@ -13,6 +13,7 @@ #include "base/scoped_temp_dir.h" #include "base/string16.h" #include "third_party/WebKit/WebKit/chromium/public/WebDatabaseObserver.h" +#include "webkit/database/database_connections.h" #include "webkit/database/database_tracker.h" class SimpleDatabaseSystem : public webkit_database::DatabaseTracker::Observer, @@ -73,6 +74,8 @@ class SimpleDatabaseSystem : public webkit_database::DatabaseTracker::Observer, Lock file_names_lock_; base::hash_map<string16, FilePath> file_names_; + + webkit_database::DatabaseConnections database_connections_; }; #endif // WEBKIT_TOOLS_TEST_SHELL_SIMPLE_DATABASE_SYSTEM_H_ diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp index bb27787..529d045 100644 --- a/webkit/tools/test_shell/test_shell.gyp +++ b/webkit/tools/test_shell/test_shell.gyp @@ -394,6 +394,7 @@ '../../database/databases_table_unittest.cc', '../../database/database_tracker_unittest.cc', '../../database/database_util_unittest.cc', + '../../database/quota_table_unittest.cc', '../../glue/bookmarklet_unittest.cc', '../../glue/context_menu_unittest.cc', '../../glue/cpp_bound_class_unittest.cc', diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index c95ad3a..d7e2030 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -198,10 +198,14 @@ 'sources': [ 'database/databases_table.cc', 'database/databases_table.h', + 'database/database_connections.cc', + 'database/database_connections.h', 'database/database_tracker.cc', 'database/database_tracker.h', 'database/database_util.cc', 'database/database_util.h', + 'database/quota_table.cc', + 'database/quota_table.h', 'database/vfs_backend.cc', 'database/vfs_backend.h', ], |