summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-08 17:18:06 +0000
committerdgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-08 17:18:06 +0000
commit5daab6118b8ec17a6329b8c6c25d40aa1f0bdf37 (patch)
tree85f092a5446325735679e5aaae937fd931466172
parent3ab3cf0e5ea81332409566f2d0a5721af6fb61ff (diff)
downloadchromium_src-5daab6118b8ec17a6329b8c6c25d40aa1f0bdf37.zip
chromium_src-5daab6118b8ec17a6329b8c6c25d40aa1f0bdf37.tar.gz
chromium_src-5daab6118b8ec17a6329b8c6c25d40aa1f0bdf37.tar.bz2
Merge 95691 - 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 TBR=dgrogan@chromium.org Review URL: http://codereview.chromium.org/7584032 git-svn-id: svn://svn.chromium.org/chrome/branches/835/src@95833 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_data_deleter.cc3
-rw-r--r--content/browser/in_process_webkit/indexed_db_callbacks.cc13
-rw-r--r--content/browser/in_process_webkit/indexed_db_callbacks.h22
-rw-r--r--content/browser/in_process_webkit/indexed_db_context.cc170
-rw-r--r--content/browser/in_process_webkit/indexed_db_context.h30
-rw-r--r--content/browser/in_process_webkit/indexed_db_dispatcher_host.cc57
-rw-r--r--content/browser/in_process_webkit/indexed_db_dispatcher_host.h13
-rw-r--r--content/browser/in_process_webkit/indexed_db_quota_client.cc43
-rw-r--r--content/browser/in_process_webkit/indexed_db_quota_client.h1
-rw-r--r--content/browser/in_process_webkit/indexed_db_quota_client_unittest.cc34
-rw-r--r--content/browser/in_process_webkit/indexed_db_transaction_callbacks.cc1
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 4c3aaac..7f09d61 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_;
@@ -202,9 +224,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 59b3b23..8d5b688 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 cd7d819..2836e84 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
@@ -36,7 +36,8 @@ class IndexedDBQuotaClientTest : public testing::Test {
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();
@@ -93,6 +94,15 @@ class IndexedDBQuotaClientTest : public testing::Test {
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) {
@@ -120,6 +130,10 @@ class IndexedDBQuotaClientTest : public testing::Test {
origins_ = origins;
}
+ void OnDeleteOriginComplete(quota::QuotaStatusCode code) {
+ delete_status_ = code;
+ }
+
ScopedTempDir temp_dir_;
int64 usage_;
std::set<GURL> origins_;
@@ -127,6 +141,8 @@ class IndexedDBQuotaClientTest : public testing::Test {
base::ScopedCallbackFactory<IndexedDBQuotaClientTest> callback_factory_;
MessageLoop message_loop_;
BrowserThread webkit_thread_;
+ BrowserThread io_thread_;
+ quota::QuotaStatusCode delete_status_;
};
@@ -190,3 +206,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_));
}