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

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: Created 4 years, 6 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 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);

Powered by Google App Engine
This is Rietveld 408576698