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); |