Chromium Code Reviews| 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(); |
|
cmumford
2016/06/23 21:44:19
nit: blocked_delete_calls_.empty() is constant tim
jsbell
2016/06/23 22:26:50
IsUpgradePendingOrRunning() should be constant tim
|
| } |
| 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()) { |
|
cmumford
2016/06/23 21:44:19
Nit: I know you're sticking with existing pattern,
jsbell
2016/06/23 22:26:50
Whoops, yeah, I'll use empty(). That was ported fr
|
| DCHECK(transactions_.empty()); |
| backing_store_ = NULL; |
| factory_->ReleaseDatabase(identifier_, forced); |