diff options
author | dgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-05 23:53:15 +0000 |
---|---|---|
committer | dgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-05 23:53:15 +0000 |
commit | 682394a2956e2797aaf844959f8fa5d623b71ff4 (patch) | |
tree | c8f963e060f58bbd5a8b6cc1ca63f7c33eeb51ed | |
parent | a4f10d1ed4c8921a2a47354f78753032d0b6a999 (diff) | |
download | chromium_src-682394a2956e2797aaf844959f8fa5d623b71ff4.zip chromium_src-682394a2956e2797aaf844959f8fa5d623b71ff4.tar.gz chromium_src-682394a2956e2797aaf844959f8fa5d623b71ff4.tar.bz2 |
Improve IndexedDB's quota support
* Check available quota before storing anything
* Inform quota manager of storage updates
* Evict an origin when quota manager requests
BUG=83652
TEST=llvm/Debug/unit_tests --gtest_filter=IndexedDBQuotaClientTest.* && llvm/Debug/browser_tests --gtest_filter=IndexedDBBrowser*
Review URL: http://codereview.chromium.org/7470008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95691 0039d316-1c4b-4281-b951-d872f2087c98
11 files changed, 342 insertions, 45 deletions
diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc index 69f7339..e8e5ab4 100644 --- a/chrome/browser/extensions/extension_data_deleter.cc +++ b/chrome/browser/extensions/extension_data_deleter.cc @@ -82,7 +82,8 @@ void ExtensionDataDeleter::DeleteLocalStorageOnWebkitThread() { void ExtensionDataDeleter::DeleteIndexedDBOnWebkitThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); - webkit_context_->indexed_db_context()->DeleteIndexedDBForOrigin(origin_id_); + webkit_context_->indexed_db_context()->DeleteIndexedDBForOrigin( + extension_url_); } void ExtensionDataDeleter::DeleteFileSystemOnFileThread() { diff --git a/content/browser/in_process_webkit/indexed_db_callbacks.cc b/content/browser/in_process_webkit/indexed_db_callbacks.cc index 7e153a1..24b2b41 100644 --- a/content/browser/in_process_webkit/indexed_db_callbacks.cc +++ b/content/browser/in_process_webkit/indexed_db_callbacks.cc @@ -28,15 +28,18 @@ void IndexedDBCallbacksBase::onBlocked() { void IndexedDBCallbacks<WebKit::WebIDBDatabase>::onSuccess( WebKit::WebIDBDatabase* idb_object) { int32 object_id = dispatcher_host()->Add(idb_object, origin_url()); - if (dispatcher_host()->Context()->quota_manager_proxy()) { - dispatcher_host()->Context()->quota_manager_proxy()->NotifyStorageAccessed( - quota::QuotaClient::kIndexedDatabase, origin_url(), - quota::kStorageTypeTemporary); - } dispatcher_host()->Send( new IndexedDBMsg_CallbacksSuccessIDBDatabase(response_id(), object_id)); } +void IndexedDBCallbacks<WebKit::WebIDBTransaction>::onSuccess( + WebKit::WebIDBTransaction* idb_object) { + int32 object_id = dispatcher_host()->Add(idb_object, origin_url()); + dispatcher_host()->Send( + new IndexedDBMsg_CallbacksSuccessIDBTransaction(response_id(), + object_id)); +} + void IndexedDBCallbacks<WebKit::WebIDBCursor>::onSuccess( WebKit::WebIDBCursor* idb_object) { int32 object_id = dispatcher_host()->Add(idb_object); diff --git a/content/browser/in_process_webkit/indexed_db_callbacks.h b/content/browser/in_process_webkit/indexed_db_callbacks.h index 40704a2..fc9ff81 100644 --- a/content/browser/in_process_webkit/indexed_db_callbacks.h +++ b/content/browser/in_process_webkit/indexed_db_callbacks.h @@ -25,9 +25,6 @@ template <class Type> struct WebIDBToMsgHelper { }; template <> struct WebIDBToMsgHelper<WebKit::WebIDBIndex> { typedef IndexedDBMsg_CallbacksSuccessIDBIndex MsgType; }; -template <> struct WebIDBToMsgHelper<WebKit::WebIDBTransaction> { - typedef IndexedDBMsg_CallbacksSuccessIDBTransaction MsgType; -}; // The code the following two classes share. class IndexedDBCallbacksBase : public WebKit::WebIDBCallbacks { @@ -73,6 +70,25 @@ class IndexedDBCallbacks : public IndexedDBCallbacksBase { }; template <> +class IndexedDBCallbacks<WebKit::WebIDBTransaction> + : public IndexedDBCallbacksBase { + public: + IndexedDBCallbacks( + IndexedDBDispatcherHost* dispatcher_host, int32 response_id, + const GURL& origin_url) + : IndexedDBCallbacksBase(dispatcher_host, response_id), + origin_url_(origin_url) { + } + + virtual void onSuccess(WebKit::WebIDBTransaction* idb_object); + const GURL& origin_url() const { return origin_url_; } + + private: + const GURL& origin_url_; + DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks); +}; + +template <> class IndexedDBCallbacks<WebKit::WebIDBDatabase> : public IndexedDBCallbacksBase { public: diff --git a/content/browser/in_process_webkit/indexed_db_context.cc b/content/browser/in_process_webkit/indexed_db_context.cc index 8e091c1..4b9a5d5 100644 --- a/content/browser/in_process_webkit/indexed_db_context.cc +++ b/content/browser/in_process_webkit/indexed_db_context.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/message_loop_proxy.h" #include "base/string_util.h" +#include "base/task.h" #include "base/utf_string_conversions.h" #include "content/browser/browser_thread.h" #include "content/browser/in_process_webkit/indexed_db_quota_client.h" @@ -18,10 +19,12 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +#include "webkit/database/database_util.h" #include "webkit/glue/webkit_glue.h" #include "webkit/quota/quota_manager.h" #include "webkit/quota/special_storage_policy.h" +using webkit_database::DatabaseUtil; using WebKit::WebIDBDatabase; using WebKit::WebIDBFactory; using WebKit::WebSecurityOrigin; @@ -56,6 +59,41 @@ const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] = const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] = FILE_PATH_LITERAL(".leveldb"); +class IndexedDBContext::IndexedDBGetUsageAndQuotaCallback : + public quota::QuotaManager::GetUsageAndQuotaCallback { + public: + IndexedDBGetUsageAndQuotaCallback(IndexedDBContext* context, + const GURL& origin_url) + : context_(context), + origin_url_(origin_url) { + } + + void Run(quota::QuotaStatusCode status, int64 usage, int64 quota) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort) + << "status was " << status; + if (status == quota::kQuotaErrorAbort) { + // We seem to no longer care to wait around for the answer. + return; + } + BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, + NewRunnableMethod(context_.get(), + &IndexedDBContext::GotUpdatedQuota, + origin_url_, + usage, + quota)); + } + + virtual void RunWithParams( + const Tuple3<quota::QuotaStatusCode, int64, int64>& params) { + Run(params.a, params.b, params.c); + } + + private: + scoped_refptr<IndexedDBContext> context_; + const GURL origin_url_; +}; + IndexedDBContext::IndexedDBContext( WebKitContext* webkit_context, quota::SpecialStoragePolicy* special_storage_policy, @@ -100,19 +138,19 @@ FilePath IndexedDBContext::GetIndexedDBFilePath( return data_path_.Append(id.append(kIndexedDBExtension)); } -void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); - // TODO(pastarmovj): Close all database connections that use that file. - file_util::Delete(file_path, false); -} - -void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) { +// Note: This is not called in response to a UI action in Content Settings. Only +// extension data deleter and quota manager currently call this. +void IndexedDBContext::DeleteIndexedDBForOrigin(const GURL& origin_url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); - // TODO(pastarmovj): Remove this check once we are safe to delete any time. - FilePath idb_file = GetIndexedDBFilePath(origin_id); - DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")), - FILE_PATH_LITERAL("chrome-extension")); - DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id)); + string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); + FilePath idb_directory = GetIndexedDBFilePath(origin_id); + if (idb_directory.BaseName().value().substr(0, strlen("chrome-extension")) == + FILE_PATH_LITERAL("chrome-extension") || + connection_count_.find(origin_url) == connection_count_.end()) { + EnsureDiskUsageCacheInitialized(origin_url); + file_util::Delete(idb_directory, true /*recursive*/); + QueryDiskAndUpdateQuotaUsage(origin_url); + } } bool IndexedDBContext::IsUnlimitedStorageGranted( @@ -137,6 +175,114 @@ void IndexedDBContext::GetAllOriginIdentifiers( } } +int64 IndexedDBContext::GetOriginDiskUsage(const GURL& origin_url) { + return ResetDiskUsageCache(origin_url); +} + +void IndexedDBContext::ConnectionOpened(const GURL& origin_url) { + if (quota_manager_proxy()) { + quota_manager_proxy()->NotifyStorageAccessed( + quota::QuotaClient::kIndexedDatabase, origin_url, + quota::kStorageTypeTemporary); + } + connection_count_[origin_url]++; + QueryAvailableQuota(origin_url); + EnsureDiskUsageCacheInitialized(origin_url); +} + +void IndexedDBContext::ConnectionClosed(const GURL& origin_url) { + DCHECK(connection_count_[origin_url] > 0); + if (quota_manager_proxy()) { + quota_manager_proxy()->NotifyStorageAccessed( + quota::QuotaClient::kIndexedDatabase, origin_url, + quota::kStorageTypeTemporary); + } + connection_count_[origin_url]--; + if (connection_count_[origin_url] == 0) { + QueryDiskAndUpdateQuotaUsage(origin_url); + connection_count_.erase(origin_url); + } +} + +void IndexedDBContext::TransactionComplete(const GURL& origin_url) { + DCHECK(connection_count_[origin_url] > 0); + QueryDiskAndUpdateQuotaUsage(origin_url); + QueryAvailableQuota(origin_url); +} + +bool IndexedDBContext::WouldBeOverQuota(const GURL& origin_url, + int64 additional_bytes) { + if (space_available_map_.find(origin_url) == space_available_map_.end()) { + // We haven't heard back from the QuotaManager yet, just let it through. + return false; + } + bool over_quota = additional_bytes > space_available_map_[origin_url]; + return over_quota; +} + +bool IndexedDBContext::IsOverQuota(const GURL& origin_url) { + const int kOneAdditionalByte = 1; + return WouldBeOverQuota(origin_url, kOneAdditionalByte); +} + quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { return quota_manager_proxy_; } + +int64 IndexedDBContext::ReadUsageFromDisk(const GURL& origin_url) const { + string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); + FilePath file_path = GetIndexedDBFilePath(origin_id); + return file_util::ComputeDirectorySize(file_path); +} + +void IndexedDBContext::EnsureDiskUsageCacheInitialized(const GURL& origin_url) { + if (origin_size_map_.find(origin_url) == origin_size_map_.end()) + ResetDiskUsageCache(origin_url); +} + +void IndexedDBContext::QueryDiskAndUpdateQuotaUsage(const GURL& origin_url) { + int64 former_disk_usage = origin_size_map_[origin_url]; + int64 current_disk_usage = ReadUsageFromDisk(origin_url); + int64 difference = current_disk_usage - former_disk_usage; + if (difference) { + origin_size_map_[origin_url] = current_disk_usage; + // quota_manager_proxy() is NULL in unit tests. + if (quota_manager_proxy()) + quota_manager_proxy()->NotifyStorageModified( + quota::QuotaClient::kIndexedDatabase, + origin_url, + quota::kStorageTypeTemporary, + difference); + } +} + +void IndexedDBContext::GotUpdatedQuota(const GURL& origin_url, int64 usage, + int64 quota) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); + space_available_map_[origin_url] = quota - usage; +} + +void IndexedDBContext::QueryAvailableQuota(const GURL& origin_url) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); + if (quota_manager_proxy()) + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + NewRunnableMethod(this, &IndexedDBContext::QueryAvailableQuota, + origin_url)); + return; + } + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!quota_manager_proxy()->quota_manager()) + return; + IndexedDBGetUsageAndQuotaCallback* callback = + new IndexedDBGetUsageAndQuotaCallback(this, origin_url); + quota_manager_proxy()->quota_manager()->GetUsageAndQuota( + origin_url, + quota::kStorageTypeTemporary, + callback); +} + +int64 IndexedDBContext::ResetDiskUsageCache(const GURL& origin_url) { + origin_size_map_[origin_url] = ReadUsageFromDisk(origin_url); + return origin_size_map_[origin_url]; +} diff --git a/content/browser/in_process_webkit/indexed_db_context.h b/content/browser/in_process_webkit/indexed_db_context.h index 408cccc..5ce0a6a 100644 --- a/content/browser/in_process_webkit/indexed_db_context.h +++ b/content/browser/in_process_webkit/indexed_db_context.h @@ -6,6 +6,8 @@ #define CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_ #pragma once +#include <map> + #include "base/basictypes.h" #include "base/file_path.h" #include "base/memory/ref_counted.h" @@ -53,16 +55,22 @@ class IndexedDBContext : public base::RefCountedThreadSafe<IndexedDBContext> { clear_local_state_on_exit_ = clear_local_state; } - // Deletes a single indexed db file. - void DeleteIndexedDBFile(const FilePath& file_path); - // Deletes all indexed db files for the given origin. - void DeleteIndexedDBForOrigin(const string16& origin_id); + void DeleteIndexedDBForOrigin(const GURL& origin_url); // Does a particular origin get unlimited storage? bool IsUnlimitedStorageGranted(const GURL& origin) const; + // Methods used in response to QuotaManager requests. void GetAllOriginIdentifiers(std::vector<string16>* origin_ids); + int64 GetOriginDiskUsage(const GURL& origin_url); + + // Methods called by IndexedDBDispatcherHost for quota support. + void ConnectionOpened(const GURL& origin_url); + void ConnectionClosed(const GURL& origin_url); + void TransactionComplete(const GURL& origin_url); + bool WouldBeOverQuota(const GURL& origin_url, int64 additional_bytes); + bool IsOverQuota(const GURL& origin_url); quota::QuotaManagerProxy* quota_manager_proxy(); @@ -72,6 +80,16 @@ class IndexedDBContext : public base::RefCountedThreadSafe<IndexedDBContext> { #endif private: + typedef std::map<GURL, int64> OriginToSizeMap; + class IndexedDBGetUsageAndQuotaCallback; + + int64 ReadUsageFromDisk(const GURL& origin_url) const; + void EnsureDiskUsageCacheInitialized(const GURL& origin_url); + void QueryDiskAndUpdateQuotaUsage(const GURL& origin_url); + void GotUpdatedQuota(const GURL& origin_url, int64 usage, int64 quota); + void QueryAvailableQuota(const GURL& origin_url); + int64 ResetDiskUsageCache(const GURL& origin_url); + scoped_ptr<WebKit::WebIDBFactory> idb_factory_; // Path where the indexed db data is stored @@ -84,6 +102,10 @@ class IndexedDBContext : public base::RefCountedThreadSafe<IndexedDBContext> { scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; + OriginToSizeMap origin_size_map_; + OriginToSizeMap space_available_map_; + std::map<GURL, unsigned int> connection_count_; + DISALLOW_COPY_AND_ASSIGN(IndexedDBContext); }; diff --git a/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc b/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc index 16ca3a7..01b152f 100644 --- a/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc +++ b/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc @@ -28,7 +28,6 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/quota/quota_manager.h" using WebKit::WebDOMStringList; using WebKit::WebExceptionCode; @@ -155,7 +154,8 @@ int32 IndexedDBDispatcherHost::Add(WebIDBDatabase* idb_database, return 0; } int32 idb_database_id = database_dispatcher_host_->map_.Add(idb_database); - database_dispatcher_host_->url_map_[idb_database_id] = origin_url; + Context()->ConnectionOpened(origin_url); + database_dispatcher_host_->database_url_map_[idb_database_id] = origin_url; return idb_database_id; } @@ -179,18 +179,21 @@ int32 IndexedDBDispatcherHost::Add(WebIDBObjectStore* idb_object_store) { return object_store_dispatcher_host_->map_.Add(idb_object_store); } -int32 IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction) { +int32 IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction, + const GURL& url) { if (!transaction_dispatcher_host_.get()) { delete idb_transaction; return 0; } int32 id = transaction_dispatcher_host_->map_.Add(idb_transaction); idb_transaction->setCallbacks(new IndexedDBTransactionCallbacks(this, id)); + transaction_dispatcher_host_->transaction_url_map_[id] = url; return id; } void IndexedDBDispatcherHost::OnIDBFactoryOpen( const IndexedDBHostMsg_FactoryOpen_Params& params) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); FilePath base_path = webkit_context_->data_path(); FilePath indexed_db_path; if (!base_path.empty()) { @@ -226,6 +229,8 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen( backingStoreType = WebKit::WebIDBFactory::SQLiteBackingStore; } + // TODO(dgrogan): Don't let a non-existing database be opened (and therefore + // created) if this origin is already over quota. Context()->GetIDBFactory()->open( params.name, new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id, @@ -255,6 +260,11 @@ void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase( webkit_glue::FilePathToWebString(indexed_db_path)); } +void IndexedDBDispatcherHost::TransactionComplete(int32 transaction_id) { + Context()->TransactionComplete( + transaction_dispatcher_host_->transaction_url_map_[transaction_id]); +} + ////////////////////////////////////////////////////////////////////// // Helper templates. // @@ -301,6 +311,10 @@ IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost( } IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() { + for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin(); + iter != database_url_map_.end(); iter++) { + parent_->Context()->ConnectionClosed(iter->second); + } } bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived( @@ -371,6 +385,10 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore( params.name, params.key_path, params.auto_increment, *idb_transaction, *ec); *object_store_id = *ec ? 0 : parent_->Add(object_store); + if (parent_->Context()->IsOverQuota( + database_url_map_[params.idb_database_id])) { + idb_transaction->abort(); + } } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore( @@ -404,7 +422,8 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetVersion( *ec = 0; idb_database->setVersion( version, - new IndexedDBCallbacks<WebIDBTransaction>(parent_, response_id), + new IndexedDBCallbacks<WebIDBTransaction>(parent_, response_id, + database_url_map_[idb_database_id]), *ec); } @@ -430,7 +449,8 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction( WebIDBTransaction* transaction = database->transaction( object_stores, mode, timeout, *ec); DCHECK(!transaction != !*ec); - *idb_transaction_id = *ec ? 0 : parent_->Add(transaction); + *idb_transaction_id = + *ec ? 0 : parent_->Add(transaction, database_url_map_[idb_database_id]); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpen( @@ -445,14 +465,12 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose( WebIDBDatabase* database = parent_->GetOrTerminateProcess( &map_, idb_database_id); database->close(); - parent_->Context()->quota_manager_proxy()->NotifyStorageAccessed( - quota::QuotaClient::kIndexedDatabase, url_map_[idb_database_id], - quota::kStorageTypeTemporary); - url_map_.erase(idb_database_id); } void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed( int32 object_id) { + parent_->Context()->ConnectionClosed(database_url_map_[object_id]); + database_url_map_.erase(object_id); parent_->DestroyObject(&map_, object_id); } @@ -704,6 +722,12 @@ void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnPut( new IndexedDBCallbacks<WebIDBKey>(parent_, params.response_id)); idb_object_store->put(params.serialized_value, params.key, params.put_mode, callbacks.release(), *idb_transaction, *ec); + if (*ec) + return; + int64 size = UTF16ToUTF8(params.serialized_value.data()).size(); + WebIDBTransactionIDToSizeMap* map = + &parent_->transaction_dispatcher_host_->transaction_size_map_; + (*map)[params.transaction_id] += size; } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDelete( @@ -761,6 +785,12 @@ void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnCreateIndex( WebIDBIndex* index = idb_object_store->createIndex( params.name, params.key_path, params.unique, *idb_transaction, *ec); *index_id = *ec ? 0 : parent_->Add(index); + WebIDBObjectIDToURLMap* transaction_url_map = + &parent_->transaction_dispatcher_host_->transaction_url_map_; + if (parent_->Context()->IsOverQuota( + (*transaction_url_map)[params.transaction_id])) { + idb_transaction->abort(); + } } void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndex( @@ -1033,10 +1063,19 @@ void IndexedDBDispatcherHost:: if (!idb_transaction) return; + // TODO(dgrogan): Tell the page the transaction aborted because of quota. + if (parent_->Context()->WouldBeOverQuota( + transaction_url_map_[transaction_id], + transaction_size_map_[transaction_id])) { + idb_transaction->abort(); + return; + } idb_transaction->didCompleteTaskEvents(); } void IndexedDBDispatcherHost::TransactionDispatcherHost::OnDestroyed( int32 object_id) { + transaction_size_map_.erase(object_id); + transaction_url_map_.erase(object_id); parent_->DestroyObject(&map_, object_id); } diff --git a/content/browser/in_process_webkit/indexed_db_dispatcher_host.h b/content/browser/in_process_webkit/indexed_db_dispatcher_host.h index 23190fb..85b97b8 100644 --- a/content/browser/in_process_webkit/indexed_db_dispatcher_host.h +++ b/content/browser/in_process_webkit/indexed_db_dispatcher_host.h @@ -45,6 +45,8 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter { virtual bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok); + void TransactionComplete(int32 transaction_id); + // A shortcut for accessing our context. IndexedDBContext* Context() { return webkit_context_->indexed_db_context(); @@ -56,7 +58,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter { int32 Add(WebKit::WebIDBDatabase* idb_database, const GURL& origin_url); int32 Add(WebKit::WebIDBIndex* idb_index); int32 Add(WebKit::WebIDBObjectStore* idb_object_store); - int32 Add(WebKit::WebIDBTransaction* idb_transaction); + int32 Add(WebKit::WebIDBTransaction* idb_transaction, const GURL& origin_url); private: virtual ~IndexedDBDispatcherHost(); @@ -82,6 +84,10 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter { template <typename ObjectType> void DestroyObject(IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id); + // Used in nested classes. + typedef std::map<int32, GURL> WebIDBObjectIDToURLMap; + typedef std::map<int32, int64> WebIDBTransactionIDToSizeMap; + class DatabaseDispatcherHost { public: explicit DatabaseDispatcherHost(IndexedDBDispatcherHost* parent); @@ -116,8 +122,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter { IndexedDBDispatcherHost* parent_; IDMap<WebKit::WebIDBDatabase, IDMapOwnPointer> map_; - typedef std::map<int32, GURL> WebIDBDatabaseIDToURLMap; - WebIDBDatabaseIDToURLMap url_map_; + WebIDBObjectIDToURLMap database_url_map_; }; class IndexDispatcherHost { @@ -254,6 +259,8 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter { IndexedDBDispatcherHost* parent_; typedef IDMap<WebKit::WebIDBTransaction, IDMapOwnPointer> MapType; MapType map_; + WebIDBObjectIDToURLMap transaction_url_map_; + WebIDBTransactionIDToSizeMap transaction_size_map_; }; // Data shared between renderer processes with the same profile. diff --git a/content/browser/in_process_webkit/indexed_db_quota_client.cc b/content/browser/in_process_webkit/indexed_db_quota_client.cc index 11cf6ce..606188b 100644 --- a/content/browser/in_process_webkit/indexed_db_quota_client.cc +++ b/content/browser/in_process_webkit/indexed_db_quota_client.cc @@ -31,6 +31,30 @@ class IndexedDBQuotaClient::HelperTask : public quota::QuotaThreadTask { scoped_refptr<IndexedDBContext> indexed_db_context_; }; +class IndexedDBQuotaClient::DeleteOriginTask : public HelperTask { + public: + DeleteOriginTask(IndexedDBQuotaClient* client, + base::MessageLoopProxy* webkit_thread_message_loop, + const GURL& origin_url, + DeletionCallback* callback) + : HelperTask(client, webkit_thread_message_loop), + origin_url_(origin_url), callback_(callback) { + } + private: + virtual void RunOnTargetThread() OVERRIDE { + indexed_db_context_->DeleteIndexedDBForOrigin(origin_url_); + } + virtual void Aborted() OVERRIDE { + callback_.reset(); + } + virtual void Completed() OVERRIDE { + callback_->Run(quota::kQuotaStatusOk); + callback_.reset(); + } + GURL origin_url_; + scoped_ptr<DeletionCallback> callback_; +}; + class IndexedDBQuotaClient::GetOriginUsageTask : public HelperTask { public: GetOriginUsageTask( @@ -43,12 +67,10 @@ class IndexedDBQuotaClient::GetOriginUsageTask : public HelperTask { private: virtual void RunOnTargetThread() OVERRIDE { - string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url_); - FilePath file_path = indexed_db_context_->GetIndexedDBFilePath(origin_id); - usage_ = 0; - usage_ = file_util::ComputeDirectorySize(file_path); + usage_ = indexed_db_context_->GetOriginDiskUsage(origin_url_); } virtual void Completed() OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); client_->DidGetOriginUsage(origin_url_, usage_); } GURL origin_url_; @@ -211,9 +233,16 @@ void IndexedDBQuotaClient::GetOriginsForHost( void IndexedDBQuotaClient::DeleteOriginData(const GURL& origin, quota::StorageType type, DeletionCallback* callback) { - // TODO(tzik): implement me - callback->Run(quota::kQuotaErrorNotSupported); - delete callback; + if (type != quota::kStorageTypeTemporary) { + callback->Run(quota::kQuotaErrorNotSupported); + return; + } + scoped_refptr<DeleteOriginTask> task( + new DeleteOriginTask(this, + webkit_thread_message_loop_, + origin, + callback)); + task->Start(); } void IndexedDBQuotaClient::DidGetOriginUsage( diff --git a/content/browser/in_process_webkit/indexed_db_quota_client.h b/content/browser/in_process_webkit/indexed_db_quota_client.h index f98f7c0..29ded7b 100644 --- a/content/browser/in_process_webkit/indexed_db_quota_client.h +++ b/content/browser/in_process_webkit/indexed_db_quota_client.h @@ -47,6 +47,7 @@ class IndexedDBQuotaClient : public quota::QuotaClient, class GetOriginsTaskBase; class GetAllOriginsTask; class GetOriginsForHostTask; + class DeleteOriginTask; typedef quota::CallbackQueueMap1 <GetUsageCallback*, diff --git a/content/browser/in_process_webkit/indexed_db_quota_client_unittest.cc b/content/browser/in_process_webkit/indexed_db_quota_client_unittest.cc index fbba54b..3f99a2b 100644 --- a/content/browser/in_process_webkit/indexed_db_quota_client_unittest.cc +++ b/content/browser/in_process_webkit/indexed_db_quota_client_unittest.cc @@ -37,7 +37,8 @@ class IndexedDBQuotaClientTest : public TestingBrowserProcessTest { usage_(0), callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), message_loop_(MessageLoop::TYPE_IO), - webkit_thread_(BrowserThread::WEBKIT, &message_loop_) { + webkit_thread_(BrowserThread::WEBKIT, &message_loop_), + io_thread_(BrowserThread::IO, &message_loop_) { TestingProfile profile; idb_context_ = profile.GetWebKitContext()->indexed_db_context(); setup_temp_dir(); @@ -96,6 +97,15 @@ class IndexedDBQuotaClientTest : public TestingBrowserProcessTest { return origins_; } + quota::QuotaStatusCode DeleteOrigin(quota::QuotaClient* client, + const GURL& origin_url) { + delete_status_ = quota::kQuotaStatusUnknown; + client->DeleteOriginData(origin_url, kTemp, callback_factory_.NewCallback( + &IndexedDBQuotaClientTest::OnDeleteOriginComplete)); + MessageLoop::current()->RunAllPending(); + return delete_status_; + } + IndexedDBContext* idb_context() { return idb_context_.get(); } void SetFileSizeTo(const FilePath& path, int size) { @@ -125,6 +135,10 @@ class IndexedDBQuotaClientTest : public TestingBrowserProcessTest { type_ = type_; } + void OnDeleteOriginComplete(quota::QuotaStatusCode code) { + delete_status_ = code; + } + ScopedTempDir temp_dir_; int64 usage_; std::set<GURL> origins_; @@ -133,6 +147,8 @@ class IndexedDBQuotaClientTest : public TestingBrowserProcessTest { base::ScopedCallbackFactory<IndexedDBQuotaClientTest> callback_factory_; MessageLoop message_loop_; BrowserThread webkit_thread_; + BrowserThread io_thread_; + quota::QuotaStatusCode delete_status_; }; @@ -196,3 +212,19 @@ TEST_F(IndexedDBQuotaClientTest, GetOriginsForType) { EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty()); } + +TEST_F(IndexedDBQuotaClientTest, DeleteOrigin) { + IndexedDBQuotaClient client( + base::MessageLoopProxy::CreateForCurrentThread(), + idb_context()); + + AddFakeIndexedDB(kOriginA, 1000); + AddFakeIndexedDB(kOriginB, 50); + EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp)); + EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp)); + + quota::QuotaStatusCode delete_status = DeleteOrigin(&client, kOriginA); + EXPECT_EQ(quota::kQuotaStatusOk, delete_status); + EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp)); + EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp)); +} diff --git a/content/browser/in_process_webkit/indexed_db_transaction_callbacks.cc b/content/browser/in_process_webkit/indexed_db_transaction_callbacks.cc index c806242..2b41a4d 100644 --- a/content/browser/in_process_webkit/indexed_db_transaction_callbacks.cc +++ b/content/browser/in_process_webkit/indexed_db_transaction_callbacks.cc @@ -23,6 +23,7 @@ void IndexedDBTransactionCallbacks::onAbort() { } void IndexedDBTransactionCallbacks::onComplete() { + dispatcher_host_->TransactionComplete(transaction_id_); dispatcher_host_->Send( new IndexedDBMsg_TransactionCallbacksComplete(transaction_id_)); } |