Commit 682394a2 authored by dgrogan@chromium.org's avatar dgrogan@chromium.org

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
parent a4f10d1e
......@@ -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() {
......
......@@ -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);
......
......@@ -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 {
......@@ -72,6 +69,25 @@ class IndexedDBCallbacks : public IndexedDBCallbacksBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
};
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 {
......
......@@ -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) {
// 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): Close all database connections that use that file.
file_util::Delete(file_path, false);
}
void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) {
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];
}
......@@ -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);
};
......
......@@ -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);
}
......@@ -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.
......
......@@ -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
if (type != quota::kStorageTypeTemporary) {
callback->Run(quota::kQuotaErrorNotSupported);
delete callback;
return;
}
scoped_refptr<DeleteOriginTask> task(
new DeleteOriginTask(this,
webkit_thread_message_loop_,
origin,
callback));
task->Start();
}
void IndexedDBQuotaClient::DidGetOriginUsage(
......
......@@ -47,6 +47,7 @@ class IndexedDBQuotaClient : public quota::QuotaClient,
class GetOriginsTaskBase;
class GetAllOriginsTask;
class GetOriginsForHostTask;
class DeleteOriginTask;
typedef quota::CallbackQueueMap1
<GetUsageCallback*,
......
......@@ -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));
}
......@@ -23,6 +23,7 @@ void IndexedDBTransactionCallbacks::onAbort() {
}
void IndexedDBTransactionCallbacks::onComplete() {
dispatcher_host_->TransactionComplete(transaction_id_);
dispatcher_host_->Send(
new IndexedDBMsg_TransactionCallbacksComplete(transaction_id_));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment