| Index: content/browser/indexed_db/indexed_db_database.cc
|
| diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
|
| index 97f47a04d14cd726d5f86b16f2b6c7a9502a7995..caa39cba7db71e5b50353b952ed9e12bb6b204c6 100644
|
| --- a/content/browser/indexed_db/indexed_db_database.cc
|
| +++ b/content/browser/indexed_db/indexed_db_database.cc
|
| @@ -233,6 +233,7 @@ IndexedDBDatabase::~IndexedDBDatabase() {
|
| DCHECK(transactions_.empty());
|
| DCHECK(pending_open_calls_.empty());
|
| DCHECK(pending_delete_calls_.empty());
|
| + DCHECK(blocked_delete_calls_.empty());
|
| }
|
|
|
| size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const {
|
| @@ -1600,7 +1601,7 @@ size_t IndexedDBDatabase::RunningUpgradeCount() const {
|
| }
|
|
|
| size_t IndexedDBDatabase::PendingDeleteCount() const {
|
| - return pending_delete_calls_.size();
|
| + return pending_delete_calls_.size() + blocked_delete_calls_.size();
|
| }
|
|
|
| void IndexedDBDatabase::ProcessPendingCalls() {
|
| @@ -1616,31 +1617,58 @@ void IndexedDBDatabase::ProcessPendingCalls() {
|
| DCHECK_EQ(1u, ConnectionCount());
|
| // Fall through would be a no-op, since transaction must complete
|
| // asynchronously.
|
| + DCHECK(IsUpgradeRunning());
|
| DCHECK(IsDeleteDatabaseBlocked());
|
| DCHECK(IsOpenConnectionBlocked());
|
| return;
|
| }
|
|
|
| - if (!IsDeleteDatabaseBlocked()) {
|
| + if (IsUpgradeRunning()) {
|
| + DCHECK_EQ(ConnectionCount(), 1UL);
|
| + return;
|
| + }
|
| +
|
| + // These delete calls were blocked by a running upgrade, and did not even
|
| + // get as far as broadcasting OnVersionChange (if needed).
|
| + {
|
| PendingDeleteCallList pending_delete_calls;
|
| pending_delete_calls_.swap(pending_delete_calls);
|
| while (!pending_delete_calls.empty()) {
|
| - // Only the first delete call will delete the database, but each must fire
|
| - // callbacks.
|
| std::unique_ptr<PendingDeleteCall> pending_delete_call(
|
| pending_delete_calls.front());
|
| pending_delete_calls.pop_front();
|
| - DeleteDatabaseFinal(pending_delete_call->callbacks());
|
| + DeleteDatabase(pending_delete_call->callbacks());
|
| }
|
| - // delete_database_final should never re-queue calls.
|
| + // DeleteDatabase should never re-queue these calls.
|
| DCHECK(pending_delete_calls_.empty());
|
| + // Fall through when complete, as pending deletes/opens may be unblocked.
|
| + }
|
| +
|
| + // These delete calls broadcast OnVersionChange (if needed) but were blocked
|
| + // by open connections.
|
| + if (!IsDeleteDatabaseBlocked()) {
|
| + PendingDeleteCallList blocked_delete_calls;
|
| + blocked_delete_calls_.swap(blocked_delete_calls);
|
| + while (!blocked_delete_calls.empty()) {
|
| + // Only the first delete call will delete the database, but each must fire
|
| + // callbacks.
|
| + std::unique_ptr<PendingDeleteCall> pending_delete_call(
|
| + blocked_delete_calls.front());
|
| + blocked_delete_calls.pop_front();
|
| + DeleteDatabaseFinal(pending_delete_call->callbacks());
|
| + }
|
| + // DeleteDatabaseFinal should never re-queue these calls.
|
| + DCHECK(blocked_delete_calls_.empty());
|
| // Fall through when complete, as pending opens may be unblocked.
|
| }
|
|
|
| + // These open calls were blocked by a pending/running upgrade or a pending
|
| + // delete.
|
| if (!IsOpenConnectionBlocked()) {
|
| PendingOpenCallList pending_open_calls;
|
| pending_open_calls_.swap(pending_open_calls);
|
| while (!pending_open_calls.empty()) {
|
| + // This may re-queue open calls if an upgrade is necessary.
|
| OpenConnection(pending_open_calls.front());
|
| pending_open_calls.pop_front();
|
| }
|
| @@ -1674,18 +1702,22 @@ void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
|
| transactions_[transaction->id()] = transaction;
|
| }
|
|
|
| +bool IndexedDBDatabase::IsUpgradeRunning() const {
|
| + return transaction_coordinator_.IsRunningVersionChangeTransaction();
|
| +}
|
| +
|
| +bool IndexedDBDatabase::IsUpgradePendingOrRunning() const {
|
| + return pending_run_version_change_transaction_call_ || IsUpgradeRunning();
|
| +}
|
| +
|
| bool IndexedDBDatabase::IsOpenConnectionBlocked() const {
|
| - return !pending_delete_calls_.empty() ||
|
| - transaction_coordinator_.IsRunningVersionChangeTransaction() ||
|
| - pending_run_version_change_transaction_call_;
|
| + return IsUpgradePendingOrRunning() || !blocked_delete_calls_.empty();
|
| }
|
|
|
| void IndexedDBDatabase::OpenConnection(
|
| const IndexedDBPendingConnection& connection) {
|
| DCHECK(backing_store_.get());
|
|
|
| - // TODO(jsbell): Should have a priority queue so that higher version
|
| - // requests are processed first. http://crbug.com/225850
|
| if (IsOpenConnectionBlocked()) {
|
| // The backing store only detects data loss when it is first opened. The
|
| // presence of existing connections means we didn't even check for data loss
|
| @@ -1812,6 +1844,7 @@ void IndexedDBDatabase::RunVersionChangeTransactionFinal(
|
| object_store_ids,
|
| blink::WebIDBTransactionModeVersionChange);
|
|
|
| + DCHECK(transaction_coordinator_.IsRunningVersionChangeTransaction());
|
| transactions_[transaction_id]->ScheduleTask(
|
| base::Bind(&IndexedDBDatabase::VersionChangeOperation,
|
| this,
|
| @@ -1823,6 +1856,12 @@ void IndexedDBDatabase::RunVersionChangeTransactionFinal(
|
|
|
| void IndexedDBDatabase::DeleteDatabase(
|
| scoped_refptr<IndexedDBCallbacks> callbacks) {
|
| + // If there's a running upgrade, the delete calls should be deferred so that
|
| + // "versionchange" is seen after "success" fires.
|
| + if (IsUpgradeRunning()) {
|
| + pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
|
| + return;
|
| + }
|
|
|
| if (IsDeleteDatabaseBlocked()) {
|
| for (const auto* connection : connections_) {
|
| @@ -1834,14 +1873,14 @@ void IndexedDBDatabase::DeleteDatabase(
|
| // OnBlocked will be fired at the request when one of the other
|
| // connections acks that the OnVersionChange was ignored.
|
|
|
| - pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
|
| + blocked_delete_calls_.push_back(new PendingDeleteCall(callbacks));
|
| return;
|
| }
|
| DeleteDatabaseFinal(callbacks);
|
| }
|
|
|
| bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
|
| - return !!ConnectionCount();
|
| + return IsUpgradePendingOrRunning() || !!ConnectionCount();
|
| }
|
|
|
| void IndexedDBDatabase::DeleteDatabaseFinal(
|
| @@ -1880,15 +1919,15 @@ void IndexedDBDatabase::ForceClose() {
|
| }
|
|
|
| void IndexedDBDatabase::VersionChangeIgnored() {
|
| - if (pending_run_version_change_transaction_call_)
|
| + if (pending_run_version_change_transaction_call_) {
|
| pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
|
| metadata_.version);
|
| + }
|
|
|
| - for (const auto& pending_delete_call : pending_delete_calls_)
|
| + for (const auto& pending_delete_call : blocked_delete_calls_)
|
| pending_delete_call->callbacks()->OnBlocked(metadata_.version);
|
| }
|
|
|
| -
|
| void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
|
| DCHECK(connections_.count(connection));
|
| DCHECK(connection->IsConnected());
|
| @@ -1924,7 +1963,7 @@ void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
|
|
|
| // TODO(jsbell): Add a test for the pending_open_calls_ cases below.
|
| if (!ConnectionCount() && !pending_open_calls_.size() &&
|
| - !pending_delete_calls_.size()) {
|
| + !blocked_delete_calls_.size()) {
|
| DCHECK(transactions_.empty());
|
| backing_store_ = NULL;
|
| factory_->ReleaseDatabase(identifier_, forced);
|
|
|