Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1215)

Unified Diff: content/browser/indexed_db/indexed_db_database.cc

Issue 2084053004: IndexedDB: Defer delete calls when there is a running upgrade (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased, made delete lists contain unique_ptrs Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);

Powered by Google App Engine
This is Rietveld 408576698