[IndexedDB] Fixed force close during pending connection open
During a force close of the database, the connections to that database
are iterated and force closed. The iteration method was not safe to
modification, and if there was a pending connection waiting to open,
that request would execute once all the other connections were
destroyed and create a new connection.
This change changes the iteration method to account for new connections
that are added during the iteration.
R=cmp@chromium.org
Bug: 941746
Change-Id: If1b3137237dc2920ad369d6ac99c963ed9c57d0c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1522330
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Reviewed-by: Chase Phillips <cmp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#640604}
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 6b5787a5..42c6e06 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -1949,10 +1949,10 @@
request->AbortForForceClose();
}
- auto it = connections_.begin();
- while (it != connections_.end()) {
- IndexedDBConnection* connection = *it++;
+ while (!connections_.empty()) {
+ IndexedDBConnection* connection = *connections_.begin();
connection->ForceClose();
+ connections_.erase(connection);
}
DCHECK(connections_.empty());
DCHECK(!active_request_);
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index ae68224..7afd674 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -315,6 +315,45 @@
EXPECT_TRUE(request2->success_called());
}
+TEST_F(IndexedDBDatabaseTest, ForceCloseWhileOpenPending) {
+ // Verify that pending connection requests are handled correctly during a
+ // ForceClose.
+ scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
+ scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
+ new MockIndexedDBDatabaseCallbacks());
+ const int64_t transaction_id1 = 1;
+ std::unique_ptr<IndexedDBPendingConnection> connection(
+ std::make_unique<IndexedDBPendingConnection>(
+ request1, callbacks1, kFakeChildProcessId, transaction_id1,
+ IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+ db_->OpenConnection(std::move(connection));
+
+ EXPECT_EQ(db_->ConnectionCount(), 1UL);
+ EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
+ EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
+ EXPECT_FALSE(backing_store_->HasOneRef()); // local and db
+
+ scoped_refptr<MockIndexedDBCallbacks> request2(
+ new MockIndexedDBCallbacks(false));
+ scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2(
+ new MockIndexedDBDatabaseCallbacks());
+ const int64_t transaction_id2 = 2;
+ std::unique_ptr<IndexedDBPendingConnection> connection2(
+ std::make_unique<IndexedDBPendingConnection>(
+ request1, callbacks1, kFakeChildProcessId, transaction_id2, 3));
+ db_->OpenConnection(std::move(connection2));
+
+ EXPECT_EQ(db_->ConnectionCount(), 1UL);
+ EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
+ EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
+ EXPECT_FALSE(backing_store_->HasOneRef()); // local and db
+
+ db_->ForceClose();
+ EXPECT_EQ(db_->ConnectionCount(), 0UL);
+ EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
+ EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
+}
+
leveldb::Status DummyOperation(IndexedDBTransaction* transaction) {
return leveldb::Status::OK();
}