Commit 1bc0f674 authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[IndexedDB] Moving IDBDatabase's PendingConnection to use ScopesLockManager

This allows scopes to be used in the DeleteDatabase call, and cleans up
some code in the IndexedDBDatabase class.

The last part of the codebase that doesn't have locks before being used
is the IndexedDBBackingStore::Initialize call. Since this happens on the
opening of the database, this can probably use just the raw database +
a WriteBatch.

Bug: 862456
Change-Id: I89c79ec89a4450e21f1ee700b007ec867b3a4f48
Reviewed-on: https://chromium-review.googlesource.com/c/1478391
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Reviewed-by: default avatarChase Phillips <cmp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#634358}
parent a88118b3
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/stl_util.h" #include "base/stl_util.h"
...@@ -32,6 +33,8 @@ ...@@ -32,6 +33,8 @@
#include "content/browser/indexed_db/indexed_db_tracing.h" #include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h" #include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/browser/indexed_db/indexed_db_value.h" #include "content/browser/indexed_db/indexed_db_value.h"
#include "content/browser/indexed_db/scopes/scope_lock.h"
#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "ipc/ipc_channel.h" #include "ipc/ipc_channel.h"
#include "storage/browser/blob/blob_data_handle.h" #include "storage/browser/blob/blob_data_handle.h"
...@@ -124,7 +127,9 @@ class IndexedDBDatabase::OpenRequest ...@@ -124,7 +127,9 @@ class IndexedDBDatabase::OpenRequest
public: public:
OpenRequest(scoped_refptr<IndexedDBDatabase> db, OpenRequest(scoped_refptr<IndexedDBDatabase> db,
std::unique_ptr<IndexedDBPendingConnection> pending_connection) std::unique_ptr<IndexedDBPendingConnection> pending_connection)
: ConnectionRequest(db), pending_(std::move(pending_connection)) {} : ConnectionRequest(db),
pending_(std::move(pending_connection)),
weak_factory_(this) {}
void Perform() override { void Perform() override {
if (db_->metadata_.id == kInvalidId) { if (db_->metadata_.id == kInvalidId) {
...@@ -200,7 +205,13 @@ class IndexedDBDatabase::OpenRequest ...@@ -200,7 +205,13 @@ class IndexedDBDatabase::OpenRequest
DCHECK_GT(new_version, old_version); DCHECK_GT(new_version, old_version);
if (db_->connections_.empty()) { if (db_->connections_.empty()) {
StartUpgrade(); std::vector<ScopesLockManager::ScopeLockRequest> lock_requests = {
{kDatabaseRangeLockLevel, GetDatabaseLockRange(db_->metadata_.id),
ScopesLockManager::LockType::kExclusive}};
db_->lock_manager_->AcquireLocks(
std::move(lock_requests),
base::BindOnce(&IndexedDBDatabase::OpenRequest::StartUpgrade,
weak_factory_.GetWeakPtr()));
return; return;
} }
...@@ -234,13 +245,19 @@ class IndexedDBDatabase::OpenRequest ...@@ -234,13 +245,19 @@ class IndexedDBDatabase::OpenRequest
if (!db_->connections_.empty()) if (!db_->connections_.empty())
return; return;
StartUpgrade(); std::vector<ScopesLockManager::ScopeLockRequest> lock_requests = {
{kDatabaseRangeLockLevel, GetDatabaseLockRange(db_->metadata_.id),
ScopesLockManager::LockType::kExclusive}};
db_->lock_manager_->AcquireLocks(
std::move(lock_requests),
base::BindOnce(&IndexedDBDatabase::OpenRequest::StartUpgrade,
weak_factory_.GetWeakPtr()));
} }
// Initiate the upgrade. The bulk of the work actually happens in // Initiate the upgrade. The bulk of the work actually happens in
// IndexedDBDatabase::VersionChangeOperation in order to kick the // IndexedDBDatabase::VersionChangeOperation in order to kick the
// transaction into the correct state. // transaction into the correct state.
void StartUpgrade() { void StartUpgrade(std::vector<ScopeLock> locks) {
connection_ = db_->CreateConnection(pending_->database_callbacks, connection_ = db_->CreateConnection(pending_->database_callbacks,
pending_->child_process_id); pending_->child_process_id);
DCHECK_EQ(db_->connections_.count(connection_.get()), 1UL); DCHECK_EQ(db_->connections_.count(connection_.get()), 1UL);
...@@ -252,11 +269,10 @@ class IndexedDBDatabase::OpenRequest ...@@ -252,11 +269,10 @@ class IndexedDBDatabase::OpenRequest
std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()),
blink::mojom::IDBTransactionMode::VersionChange, blink::mojom::IDBTransactionMode::VersionChange,
new IndexedDBBackingStore::Transaction(db_->backing_store())); new IndexedDBBackingStore::Transaction(db_->backing_store()));
db_->RegisterAndScheduleTransaction(transaction);
transaction->ScheduleTask( transaction->ScheduleTask(
base::BindOnce(&IndexedDBDatabase::VersionChangeOperation, db_, base::BindOnce(&IndexedDBDatabase::VersionChangeOperation, db_,
pending_->version, pending_->callbacks)); pending_->version, pending_->callbacks));
transaction->Start(std::move(locks));
} }
// Called when the upgrade transaction has started executing. // Called when the upgrade transaction has started executing.
...@@ -296,6 +312,7 @@ class IndexedDBDatabase::OpenRequest ...@@ -296,6 +312,7 @@ class IndexedDBDatabase::OpenRequest
// transferred to the IndexedDBDispatcherHost via OnUpgradeNeeded. // transferred to the IndexedDBDispatcherHost via OnUpgradeNeeded.
std::unique_ptr<IndexedDBConnection> connection_; std::unique_ptr<IndexedDBConnection> connection_;
base::WeakPtrFactory<OpenRequest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(OpenRequest); DISALLOW_COPY_AND_ASSIGN(OpenRequest);
}; };
...@@ -304,12 +321,18 @@ class IndexedDBDatabase::DeleteRequest ...@@ -304,12 +321,18 @@ class IndexedDBDatabase::DeleteRequest
public: public:
DeleteRequest(scoped_refptr<IndexedDBDatabase> db, DeleteRequest(scoped_refptr<IndexedDBDatabase> db,
scoped_refptr<IndexedDBCallbacks> callbacks) scoped_refptr<IndexedDBCallbacks> callbacks)
: ConnectionRequest(db), callbacks_(callbacks) {} : ConnectionRequest(db), callbacks_(callbacks), weak_factory_(this) {}
void Perform() override { void Perform() override {
if (db_->connections_.empty()) { if (db_->connections_.empty()) {
// No connections, so delete immediately. // No connections, so delete immediately.
DoDelete(); std::vector<ScopesLockManager::ScopeLockRequest> lock_requests = {
{kDatabaseRangeLockLevel, GetDatabaseLockRange(db_->metadata_.id),
ScopesLockManager::LockType::kExclusive}};
db_->lock_manager_->AcquireLocks(
std::move(lock_requests),
base::BindOnce(&IndexedDBDatabase::DeleteRequest::DoDelete,
weak_factory_.GetWeakPtr()));
return; return;
} }
...@@ -328,10 +351,17 @@ class IndexedDBDatabase::DeleteRequest ...@@ -328,10 +351,17 @@ class IndexedDBDatabase::DeleteRequest
void OnConnectionClosed(IndexedDBConnection* connection) override { void OnConnectionClosed(IndexedDBConnection* connection) override {
if (!db_->connections_.empty()) if (!db_->connections_.empty())
return; return;
DoDelete();
std::vector<ScopesLockManager::ScopeLockRequest> lock_requests = {
{kDatabaseRangeLockLevel, GetDatabaseLockRange(db_->metadata_.id),
ScopesLockManager::LockType::kExclusive}};
db_->lock_manager_->AcquireLocks(
std::move(lock_requests),
base::BindOnce(&IndexedDBDatabase::DeleteRequest::DoDelete,
weak_factory_.GetWeakPtr()));
} }
void DoDelete() { void DoDelete(std::vector<ScopeLock> locks) {
Status s; Status s;
if (db_->backing_store_) if (db_->backing_store_)
s = db_->backing_store_->DeleteDatabase(db_->metadata_.name); s = db_->backing_store_->DeleteDatabase(db_->metadata_.name);
...@@ -374,6 +404,7 @@ class IndexedDBDatabase::DeleteRequest ...@@ -374,6 +404,7 @@ class IndexedDBDatabase::DeleteRequest
private: private:
scoped_refptr<IndexedDBCallbacks> callbacks_; scoped_refptr<IndexedDBCallbacks> callbacks_;
base::WeakPtrFactory<DeleteRequest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DeleteRequest); DISALLOW_COPY_AND_ASSIGN(DeleteRequest);
}; };
...@@ -1806,18 +1837,28 @@ Status IndexedDBDatabase::VersionChangeOperation( ...@@ -1806,18 +1837,28 @@ Status IndexedDBDatabase::VersionChangeOperation(
return Status::OK(); return Status::OK();
} }
void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, void IndexedDBDatabase::TransactionCreated() {
bool committed) { UMA_HISTOGRAM_COUNTS_1000(
IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", "WebCore.IndexedDB.Database.OutstandingTransactionCount",
transaction->id()); transaction_count_);
++transaction_count_;
}
void IndexedDBDatabase::TransactionFinished(
blink::mojom::IDBTransactionMode mode,
bool committed) {
--transaction_count_; --transaction_count_;
DCHECK_GE(transaction_count_, 0); DCHECK_GE(transaction_count_, 0);
// TODO(dmurph): To help remove this integration with IndexedDBDatabase, make
// a 'committed' listener closure on all transactions. Then the request can
// just listen for that.
// This may be an unrelated transaction finishing while waiting for // This may be an unrelated transaction finishing while waiting for
// connections to close, or the actual upgrade transaction from an active // connections to close, or the actual upgrade transaction from an active
// request. Notify the active request if it's the latter. // request. Notify the active request if it's the latter.
if (active_request_ && if (active_request_ &&
transaction->mode() == blink::mojom::IDBTransactionMode::VersionChange) { mode == blink::mojom::IDBTransactionMode::VersionChange) {
active_request_->UpgradeTransactionFinished(committed); active_request_->UpgradeTransactionFinished(committed);
} }
} }
...@@ -1861,11 +1902,6 @@ void IndexedDBDatabase::RegisterAndScheduleTransaction( ...@@ -1861,11 +1902,6 @@ void IndexedDBDatabase::RegisterAndScheduleTransaction(
IndexedDBTransaction* transaction) { IndexedDBTransaction* transaction) {
IDB_TRACE1("IndexedDBDatabase::RegisterAndScheduleTransaction", "txn.id", IDB_TRACE1("IndexedDBDatabase::RegisterAndScheduleTransaction", "txn.id",
transaction->id()); transaction->id());
UMA_HISTOGRAM_COUNTS_1000(
"WebCore.IndexedDB.Database.OutstandingTransactionCount",
transaction_count_);
transaction_count_++;
std::vector<ScopesLockManager::ScopeLockRequest> lock_requests; std::vector<ScopesLockManager::ScopeLockRequest> lock_requests;
lock_requests.reserve(1 + transaction->scope().size()); lock_requests.reserve(1 + transaction->scope().size());
lock_requests.emplace_back( lock_requests.emplace_back(
......
...@@ -103,8 +103,8 @@ class CONTENT_EXPORT IndexedDBDatabase ...@@ -103,8 +103,8 @@ class CONTENT_EXPORT IndexedDBDatabase
int64_t object_store_id, int64_t object_store_id,
const base::string16& new_name); const base::string16& new_name);
// Returns a pointer to a newly created transaction. The object is owned // TODO(dmurph): Remove this method and have transactions be directly
// by the connection. // scheduled using the lock manager.
void RegisterAndScheduleTransaction(IndexedDBTransaction* transaction); void RegisterAndScheduleTransaction(IndexedDBTransaction* transaction);
void Close(IndexedDBConnection* connection, bool forced); void Close(IndexedDBConnection* connection, bool forced);
void ForceClose(); void ForceClose();
...@@ -136,7 +136,9 @@ class CONTENT_EXPORT IndexedDBDatabase ...@@ -136,7 +136,9 @@ class CONTENT_EXPORT IndexedDBDatabase
return lock_manager_; return lock_manager_;
} }
void TransactionFinished(IndexedDBTransaction* transaction, bool committed); void TransactionCreated();
void TransactionFinished(blink::mojom::IDBTransactionMode mode,
bool committed);
void AbortAllTransactionsForConnections(); void AbortAllTransactionsForConnections();
......
...@@ -119,6 +119,8 @@ IndexedDBTransaction::IndexedDBTransaction( ...@@ -119,6 +119,8 @@ IndexedDBTransaction::IndexedDBTransaction(
IDB_ASYNC_TRACE_BEGIN("IndexedDBTransaction::lifetime", this); IDB_ASYNC_TRACE_BEGIN("IndexedDBTransaction::lifetime", this);
callbacks_ = connection_->callbacks(); callbacks_ = connection_->callbacks();
database_ = connection_->database(); database_ = connection_->database();
if (database_)
database_->TransactionCreated();
diagnostics_.tasks_scheduled = 0; diagnostics_.tasks_scheduled = 0;
diagnostics_.tasks_completed = 0; diagnostics_.tasks_completed = 0;
...@@ -237,7 +239,7 @@ void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { ...@@ -237,7 +239,7 @@ void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) {
if (callbacks_.get()) if (callbacks_.get())
callbacks_->OnAbort(*this, error); callbacks_->OnAbort(*this, error);
database_->TransactionFinished(this, false); database_->TransactionFinished(mode_, false);
// RemoveTransaction will delete |this|. // RemoveTransaction will delete |this|.
// Note: During force-close situations, the connection can be destroyed during // Note: During force-close situations, the connection can be destroyed during
...@@ -460,7 +462,7 @@ leveldb::Status IndexedDBTransaction::CommitPhaseTwo() { ...@@ -460,7 +462,7 @@ leveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
if (!pending_observers_.empty() && connection_) if (!pending_observers_.empty() && connection_)
connection_->ActivatePendingObservers(std::move(pending_observers_)); connection_->ActivatePendingObservers(std::move(pending_observers_));
database_->TransactionFinished(this, true); database_->TransactionFinished(mode_, true);
// RemoveTransaction will delete |this|. // RemoveTransaction will delete |this|.
connection_->RemoveTransaction(id_); connection_->RemoveTransaction(id_);
return s; return s;
...@@ -479,7 +481,7 @@ leveldb::Status IndexedDBTransaction::CommitPhaseTwo() { ...@@ -479,7 +481,7 @@ leveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
"Internal error committing transaction."); "Internal error committing transaction.");
} }
callbacks_->OnAbort(*this, error); callbacks_->OnAbort(*this, error);
database_->TransactionFinished(this, false); database_->TransactionFinished(mode_, false);
} }
return s; return s;
} }
......
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