| 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 de9895b10470a0c32c2cfffbffd8d08983f2dd10..0835c8aa2cdc35f42841e6829e23109faadd8789 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 {
|
| @@ -1636,31 +1637,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()) {
|
| - std::list<PendingDeleteCall*> pending_delete_calls;
|
| + 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).
|
| + {
|
| + std::list<std::unique_ptr<PendingDeleteCall>> pending_delete_calls;
|
| pending_delete_calls_.swap(pending_delete_calls);
|
| while (!pending_delete_calls.empty()) {
|
| + std::unique_ptr<PendingDeleteCall> pending_delete_call(
|
| + std::move(pending_delete_calls.front()));
|
| + pending_delete_calls.pop_front();
|
| + DeleteDatabase(pending_delete_call->callbacks());
|
| + }
|
| + // 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()) {
|
| + std::list<std::unique_ptr<PendingDeleteCall>> 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(
|
| - pending_delete_calls.front());
|
| - pending_delete_calls.pop_front();
|
| + std::move(blocked_delete_calls.front()));
|
| + blocked_delete_calls.pop_front();
|
| DeleteDatabaseFinal(pending_delete_call->callbacks());
|
| }
|
| - // delete_database_final should never re-queue calls.
|
| - DCHECK(pending_delete_calls_.empty());
|
| + // 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()) {
|
| std::queue<IndexedDBPendingConnection> 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();
|
| }
|
| @@ -1694,18 +1722,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
|
| @@ -1832,6 +1864,7 @@ void IndexedDBDatabase::RunVersionChangeTransactionFinal(
|
| object_store_ids,
|
| blink::WebIDBTransactionModeVersionChange);
|
|
|
| + DCHECK(transaction_coordinator_.IsRunningVersionChangeTransaction());
|
| transactions_[transaction_id]->ScheduleTask(
|
| base::Bind(&IndexedDBDatabase::VersionChangeOperation,
|
| this,
|
| @@ -1843,6 +1876,13 @@ 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(
|
| + std::unique_ptr<PendingDeleteCall>(new PendingDeleteCall(callbacks)));
|
| + return;
|
| + }
|
|
|
| if (IsDeleteDatabaseBlocked()) {
|
| for (const auto* connection : connections_) {
|
| @@ -1854,14 +1894,15 @@ 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(
|
| + std::unique_ptr<PendingDeleteCall>(new PendingDeleteCall(callbacks)));
|
| return;
|
| }
|
| DeleteDatabaseFinal(callbacks);
|
| }
|
|
|
| bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
|
| - return !!ConnectionCount();
|
| + return IsUpgradePendingOrRunning() || !!ConnectionCount();
|
| }
|
|
|
| void IndexedDBDatabase::DeleteDatabaseFinal(
|
| @@ -1900,15 +1941,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());
|
| @@ -1944,7 +1985,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_.empty() &&
|
| - pending_delete_calls_.empty()) {
|
| + blocked_delete_calls_.empty()) {
|
| DCHECK(transactions_.empty());
|
| backing_store_ = NULL;
|
| factory_->ReleaseDatabase(identifier_, forced);
|
|
|