mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 618590 Part 3: When a page is destroyed, abort any running indexedDB transactions. r=bent a=blocker
This commit is contained in:
parent
ddbaa55a08
commit
7df9624ca1
@ -1229,7 +1229,7 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
|
||||
indexedDB::IndexedDatabaseManager* idbManager =
|
||||
indexedDB::IndexedDatabaseManager::Get();
|
||||
if (idbManager) {
|
||||
idbManager->CloseDatabasesForWindow(this);
|
||||
idbManager->AbortCloseDatabasesForWindow(this);
|
||||
}
|
||||
|
||||
ClearAllTimeouts();
|
||||
|
@ -545,7 +545,7 @@ IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::CloseDatabasesForWindow(nsPIDOMWindow* aWindow)
|
||||
IndexedDatabaseManager::AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
@ -553,10 +553,18 @@ IndexedDatabaseManager::CloseDatabasesForWindow(nsPIDOMWindow* aWindow)
|
||||
nsAutoTArray<IDBDatabase*, 50> liveDatabases;
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
|
||||
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
|
||||
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
|
||||
IDBDatabase*& database = liveDatabases[index];
|
||||
if (database->Owner() == aWindow && NS_FAILED(database->Close())) {
|
||||
NS_WARNING("Failed to close database for dying window!");
|
||||
if (database->Owner() == aWindow) {
|
||||
if (NS_FAILED(database->Close())) {
|
||||
NS_WARNING("Failed to close database for dying window!");
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
pool->AbortTransactionsForDatabase(database);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +100,10 @@ public:
|
||||
const nsAString& aVersion,
|
||||
AsyncConnectionHelper* aHelper);
|
||||
|
||||
// Called when a window is being purged from the bfcache in order to force any
|
||||
// live database objects to close themselves.
|
||||
void CloseDatabasesForWindow(nsPIDOMWindow* aWindow);
|
||||
// Called when a window is being purged from the bfcache or the user leaves
|
||||
// a page which isn't going into the bfcache. Forces any live database
|
||||
// objects to close themselves and aborts any running transactions.
|
||||
void AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
// Used to check if there are running transactions in a given window.
|
||||
bool HasOpenTransactions(nsPIDOMWindow* aWindow);
|
||||
|
@ -517,6 +517,55 @@ TransactionThreadPool::WaitForAllDatabasesToComplete(
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TransactionThreadPool::AbortTransactionsForDatabase(IDBDatabase* aDatabase)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aDatabase, "Null pointer!");
|
||||
|
||||
// Get list of transactions for this database id
|
||||
DatabaseTransactionInfo* dbTransactionInfo;
|
||||
if (!mTransactionsInProgress.Get(aDatabase->Id(), &dbTransactionInfo)) {
|
||||
// If there are no running transactions, there can't be any pending ones
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoTArray<nsRefPtr<IDBTransaction>, 50> transactions;
|
||||
|
||||
// Collect any running transactions
|
||||
nsTArray<TransactionInfo>& transactionsInProgress =
|
||||
dbTransactionInfo->transactions;
|
||||
|
||||
PRUint32 transactionCount = transactionsInProgress.Length();
|
||||
NS_ASSERTION(transactionCount, "Should never be 0!");
|
||||
|
||||
for (PRUint32 index = 0; index < transactionCount; index++) {
|
||||
// See if any transaction belongs to this IDBDatabase instance
|
||||
IDBTransaction* transaction = transactionsInProgress[index].transaction;
|
||||
if (transaction->Database() == aDatabase) {
|
||||
transactions.AppendElement(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect any pending transactions.
|
||||
for (PRUint32 index = 0; index < mDelayedDispatchQueue.Length(); index++) {
|
||||
// See if any transaction belongs to this IDBDatabase instance
|
||||
IDBTransaction* transaction = mDelayedDispatchQueue[index].transaction;
|
||||
if (transaction->Database() == aDatabase) {
|
||||
transactions.AppendElement(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
// Abort transactions. Do this after collecting the transactions in case
|
||||
// calling Abort() modifies the data structures we're iterating above.
|
||||
for (PRUint32 index = 0; index < transactions.Length(); index++) {
|
||||
// This can fail, for example if the transaction is in the process of
|
||||
// being comitted. That is expected and fine, so we ignore any returned
|
||||
// errors.
|
||||
transactions[index]->Abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TransactionThreadPool::HasTransactionsForDatabase(IDBDatabase* aDatabase)
|
||||
{
|
||||
|
@ -84,7 +84,11 @@ public:
|
||||
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
|
||||
nsIRunnable* aCallback);
|
||||
|
||||
// Returns true iff there are running or pending transactions for aDatabase
|
||||
// Abort all transactions, unless they are already in the process of being
|
||||
// committed, for aDatabase.
|
||||
void AbortTransactionsForDatabase(IDBDatabase* aDatabase);
|
||||
|
||||
// Returns true iff there are running or pending transactions for aDatabase.
|
||||
bool HasTransactionsForDatabase(IDBDatabase* aDatabase);
|
||||
|
||||
protected:
|
||||
|
@ -51,6 +51,7 @@ TEST_FILES = \
|
||||
event_propagation_iframe.html \
|
||||
exceptions_in_success_events_iframe.html \
|
||||
helpers.js \
|
||||
leaving_page_iframe.html \
|
||||
test_add_twice_failure.html \
|
||||
test_bad_keypath.html \
|
||||
test_bfcache.html \
|
||||
@ -73,6 +74,7 @@ TEST_FILES = \
|
||||
test_indexes.html \
|
||||
test_indexes_bad_values.html \
|
||||
test_key_requirements.html \
|
||||
test_leaving_page.html \
|
||||
test_objectCursors.html \
|
||||
test_objectStore_inline_autoincrement_key_added_on_put.html \
|
||||
test_objectStore_remove_values.html \
|
||||
|
@ -40,10 +40,11 @@
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = function(event) {
|
||||
db.deleteObjectStore("foo");
|
||||
|
||||
testResult = "finished";
|
||||
testException = undefined;
|
||||
finishTest();
|
||||
request.transaction.oncomplete = function(event) {
|
||||
testResult = "finished";
|
||||
testException = undefined;
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
45
dom/indexedDB/test/leaving_page_iframe.html
Normal file
45
dom/indexedDB/test/leaving_page_iframe.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var db;
|
||||
function startDBWork() {
|
||||
mozIndexedDB.open(parent.location).onsuccess = function(e) {
|
||||
db = e.target.result;
|
||||
db.setVersion("1.0").onsuccess = function(e) {
|
||||
var trans = e.target.transaction;
|
||||
if (db.objectStoreNames.contains("mystore")) {
|
||||
db.deleteObjectStore("mystore");
|
||||
}
|
||||
var store = db.createObjectStore("mystore");
|
||||
store.add({ hello: "world" }, 42);
|
||||
trans.oncomplete = madeMod;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function madeMod() {
|
||||
var trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
|
||||
var store = trans.
|
||||
objectStore("mystore");
|
||||
trans.oncomplete = function() {
|
||||
parent.postMessage("didcommit", "*");
|
||||
}
|
||||
|
||||
store.put({ hello: "officer" }, 42).onsuccess = function(e) {
|
||||
// Make this transaction run until the end of time or until the page is
|
||||
// navigated away, whichever comes first.
|
||||
function doGet() {
|
||||
store.get(42).onsuccess = doGet;
|
||||
}
|
||||
doGet();
|
||||
document.location = "about:blank";
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="startDBWork();">
|
||||
This is page one.
|
||||
</body>
|
||||
</html>
|
49
dom/indexedDB/test/test_leaving_page.html
Normal file
49
dom/indexedDB/test/test_leaving_page.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Leaving Page Test</title>
|
||||
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<iframe id="inner"></iframe>
|
||||
<a id="a" href="leaving_page_iframe.html"></a>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
onmessage = function(e) {
|
||||
ok(false, "gotmessage: " + e.data);
|
||||
}
|
||||
function testSteps()
|
||||
{
|
||||
var iframe = $("inner");
|
||||
iframe.src = "leaving_page_iframe.html";
|
||||
iframe.onload = continueToNextStep;
|
||||
yield;
|
||||
is(iframe.contentWindow.location.href, $("a").href,
|
||||
"should navigate to iframe page");
|
||||
yield;
|
||||
is(iframe.contentWindow.location.href, "about:blank",
|
||||
"should nagivate to about:blank");
|
||||
|
||||
let request = mozIndexedDB.open(location);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
db.transaction(["mystore"]).objectStore("mystore").get(42).onsuccess =
|
||||
grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
is(event.target.result.hello, "world", "second modification rolled back");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user