зеркало из https://github.com/mozilla/gecko-dev.git
Bug 605019: Evict entries in the bfcache if they are holding open a database which is being upgraded. r=bent/smaug a=blocker
This commit is contained in:
Родитель
bcb3935aa9
Коммит
5ec63c5bb2
|
@ -107,6 +107,7 @@ struct JSObject;
|
|||
class nsFrameLoader;
|
||||
class nsIBoxObject;
|
||||
class imgIRequest;
|
||||
class nsISHEntry;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
@ -450,11 +451,16 @@ public:
|
|||
|
||||
nsIPresShell* GetShell() const
|
||||
{
|
||||
return mShellIsHidden ? nsnull : mPresShell;
|
||||
return GetBFCacheEntry() ? nsnull : mPresShell;
|
||||
}
|
||||
|
||||
void SetShellHidden(PRBool aHide) { mShellIsHidden = aHide; }
|
||||
PRBool ShellIsHidden() const { return mShellIsHidden; }
|
||||
void SetBFCacheEntry(nsISHEntry* aSHEntry) {
|
||||
mSHEntry = aSHEntry;
|
||||
// Doing this just to keep binary compat for the gecko 2.0 release
|
||||
mShellIsHidden = !!aSHEntry;
|
||||
}
|
||||
|
||||
nsISHEntry* GetBFCacheEntry() const { return mSHEntry; }
|
||||
|
||||
/**
|
||||
* Return the parent document of this document. Will return null
|
||||
|
@ -1594,6 +1600,8 @@ protected:
|
|||
// document in it.
|
||||
PRPackedBool mIsInitialDocumentInWindow;
|
||||
|
||||
// True if we're currently bfcached. This is only here for binary compat.
|
||||
// Remove once the gecko 2.0 has branched and just use mSHEntry instead.
|
||||
PRPackedBool mShellIsHidden;
|
||||
|
||||
PRPackedBool mIsRegularHTML;
|
||||
|
@ -1706,6 +1714,10 @@ protected:
|
|||
nsCOMPtr<nsIDocumentEncoder> mCachedEncoder;
|
||||
|
||||
AnimationListenerList mAnimationFrameListeners;
|
||||
|
||||
// The session history entry in which we're currently bf-cached. Non-null
|
||||
// if and only if we're currently in the bfcache.
|
||||
nsISHEntry* mSHEntry;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
|
||||
|
|
|
@ -3176,7 +3176,7 @@ nsDocument::doCreateShell(nsPresContext* aContext,
|
|||
|
||||
NS_ASSERTION(!mPresShell, "We have a presshell already!");
|
||||
|
||||
NS_ENSURE_FALSE(mShellIsHidden, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_FALSE(GetBFCacheEntry(), NS_ERROR_FAILURE);
|
||||
|
||||
FillStyleSet(aStyleSet);
|
||||
|
||||
|
|
|
@ -250,6 +250,12 @@ interface nsISHEntry : nsIHistoryEntry
|
|||
attribute unsigned long long docshellID;
|
||||
};
|
||||
|
||||
[scriptable, uuid(e0b0ac6d-cb29-4be2-b685-1755d6301a69)]
|
||||
interface nsISHEntryInternal : nsISupports
|
||||
{
|
||||
[notxpcom] void RemoveFromBFCacheAsync();
|
||||
[notxpcom] void RemoveFromBFCacheSync();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
// {BFD1A791-AD9F-11d3-BDC7-0050040A9B44}
|
||||
|
|
|
@ -165,10 +165,10 @@ nsSHEntry::~nsSHEntry()
|
|||
mChildren.EnumerateForwards(ClearParentPtr, nsnull);
|
||||
mChildren.Clear();
|
||||
|
||||
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
|
||||
DropPresentationState();
|
||||
if (viewer) {
|
||||
viewer->Destroy();
|
||||
if (mContentViewer) {
|
||||
// RemoveFromBFCacheSync is virtual, so call the nsSHEntry version
|
||||
// explicitly
|
||||
nsSHEntry::RemoveFromBFCacheSync();
|
||||
}
|
||||
|
||||
mEditorData = nsnull;
|
||||
|
@ -187,8 +187,8 @@ nsSHEntry::~nsSHEntry()
|
|||
// nsSHEntry: nsISupports
|
||||
//*****************************************************************************
|
||||
|
||||
NS_IMPL_ISUPPORTS4(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry,
|
||||
nsIMutationObserver)
|
||||
NS_IMPL_ISUPPORTS5(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry,
|
||||
nsIMutationObserver, nsISHEntryInternal)
|
||||
|
||||
//*****************************************************************************
|
||||
// nsSHEntry: nsISHEntry
|
||||
|
@ -254,7 +254,7 @@ nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
|
|||
// the contentviewer
|
||||
mDocument = do_QueryInterface(domDoc);
|
||||
if (mDocument) {
|
||||
mDocument->SetShellHidden(PR_TRUE);
|
||||
mDocument->SetBFCacheEntry(this);
|
||||
mDocument->AddMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
@ -747,7 +747,7 @@ nsSHEntry::DropPresentationState()
|
|||
nsRefPtr<nsSHEntry> kungFuDeathGrip = this;
|
||||
|
||||
if (mDocument) {
|
||||
mDocument->SetShellHidden(PR_FALSE);
|
||||
mDocument->SetBFCacheEntry(nsnull);
|
||||
mDocument->RemoveMutationObserver(this);
|
||||
mDocument = nsnull;
|
||||
}
|
||||
|
@ -810,7 +810,7 @@ nsSHEntry::CharacterDataChanged(nsIDocument* aDocument,
|
|||
nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
{
|
||||
DocumentMutated();
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -829,7 +829,7 @@ nsSHEntry::AttributeChanged(nsIDocument* aDocument,
|
|||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType)
|
||||
{
|
||||
DocumentMutated();
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -838,7 +838,7 @@ nsSHEntry::ContentAppended(nsIDocument* aDocument,
|
|||
nsIContent* aFirstNewContent,
|
||||
PRInt32 /* unused */)
|
||||
{
|
||||
DocumentMutated();
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -847,7 +847,7 @@ nsSHEntry::ContentInserted(nsIDocument* aDocument,
|
|||
nsIContent* aChild,
|
||||
PRInt32 /* unused */)
|
||||
{
|
||||
DocumentMutated();
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -857,7 +857,7 @@ nsSHEntry::ContentRemoved(nsIDocument* aDocument,
|
|||
PRInt32 aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
DocumentMutated();
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -885,10 +885,27 @@ public:
|
|||
};
|
||||
|
||||
void
|
||||
nsSHEntry::DocumentMutated()
|
||||
nsSHEntry::RemoveFromBFCacheSync()
|
||||
{
|
||||
NS_ASSERTION(mContentViewer && mDocument,
|
||||
"we shouldn't still be observing the doc");
|
||||
"we're not in the bfcache!");
|
||||
|
||||
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
|
||||
DropPresentationState();
|
||||
|
||||
// Warning! The call to DropPresentationState could have dropped the last
|
||||
// reference to this nsSHEntry, so no accessing members beyond here.
|
||||
|
||||
if (viewer) {
|
||||
viewer->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntry::RemoveFromBFCacheAsync()
|
||||
{
|
||||
NS_ASSERTION(mContentViewer && mDocument,
|
||||
"we're not in the bfcache!");
|
||||
|
||||
// Release the reference to the contentviewer asynchronously so that the
|
||||
// document doesn't get nuked mid-mutation.
|
||||
|
|
|
@ -63,7 +63,8 @@
|
|||
|
||||
class nsSHEntry : public nsISHEntry,
|
||||
public nsISHContainer,
|
||||
public nsIMutationObserver
|
||||
public nsIMutationObserver,
|
||||
public nsISHEntryInternal
|
||||
{
|
||||
public:
|
||||
nsSHEntry();
|
||||
|
@ -72,6 +73,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHISTORYENTRY
|
||||
NS_DECL_NSISHENTRY
|
||||
NS_DECL_NSISHENTRYINTERNAL
|
||||
NS_DECL_NSISHCONTAINER
|
||||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
|
||||
|
@ -86,7 +88,6 @@ public:
|
|||
|
||||
private:
|
||||
~nsSHEntry();
|
||||
void DocumentMutated();
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mReferrerURI;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsDOMLists.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
class nsIScriptContext;
|
||||
class nsPIDOMWindow;
|
||||
|
@ -109,6 +110,13 @@ public:
|
|||
return mOwner;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument> GetOwnerDocument()
|
||||
{
|
||||
NS_ASSERTION(mOwner, "This should never be null!");
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOwner->GetExtantDocument());
|
||||
return doc.forget();
|
||||
}
|
||||
|
||||
bool IsQuotaDisabled();
|
||||
|
||||
nsCString& Origin()
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "IDBFactory.h"
|
||||
#include "LazyIdleThread.h"
|
||||
#include "TransactionThreadPool.h"
|
||||
#include "nsISHEntry.h"
|
||||
|
||||
// The amount of time, in milliseconds, that our IO thread will stay alive
|
||||
// after the last event it processes.
|
||||
|
@ -162,18 +163,33 @@ public:
|
|||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Fire version change events at all of the databases that are not already
|
||||
// closed.
|
||||
// closed. Also kick bfcached documents out of bfcache.
|
||||
for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) {
|
||||
nsRefPtr<IDBDatabase>& database = mWaitingDatabases[index];
|
||||
|
||||
if (!database->IsClosed()) {
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event(IDBVersionChangeEvent::Create(mVersion));
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
|
||||
|
||||
PRBool dummy;
|
||||
database->DispatchEvent(event, &dummy);
|
||||
if (database->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First check if the document the IDBDatabase is part of is bfcached
|
||||
nsCOMPtr<nsIDocument> ownerDoc = database->GetOwnerDocument();
|
||||
nsISHEntry* shEntry;
|
||||
if (ownerDoc && (shEntry = ownerDoc->GetBFCacheEntry())) {
|
||||
nsCOMPtr<nsISHEntryInternal> sheInternal = do_QueryInterface(shEntry);
|
||||
if (sheInternal) {
|
||||
sheInternal->RemoveFromBFCacheSync();
|
||||
}
|
||||
NS_ASSERTION(database->IsClosed(),
|
||||
"Kicking doc out of bfcache should have closed database");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise fire a versionchange event.
|
||||
nsCOMPtr<nsIDOMEvent> event(IDBVersionChangeEvent::Create(mVersion));
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
|
||||
|
||||
PRBool dummy;
|
||||
database->DispatchEvent(event, &dummy);
|
||||
}
|
||||
|
||||
// Now check to see if any didn't close. If there are some running still
|
||||
|
|
|
@ -45,10 +45,13 @@ include $(DEPTH)/config/autoconf.mk
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
TEST_FILES = \
|
||||
bfcache_iframe1.html \
|
||||
bfcache_iframe2.html \
|
||||
event_propagation_iframe.html \
|
||||
helpers.js \
|
||||
test_add_twice_failure.html \
|
||||
test_bad_keypath.html \
|
||||
test_bfcache.html \
|
||||
test_clear.html \
|
||||
test_create_index.html \
|
||||
test_create_objectStore.html \
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
moz_indexedDB.open(parent.location).onsuccess = function(e) {
|
||||
var db = e.result;
|
||||
// This should never be called
|
||||
db.onversionchange = function(e) {
|
||||
db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
|
||||
}
|
||||
db.setVersion("1.0").onsuccess = function(e) {
|
||||
trans = e.transaction;
|
||||
if (db.objectStoreNames.contains("mystore")) {
|
||||
db.deleteObjectStore("mystore");
|
||||
}
|
||||
var store = db.createObjectStore("mystore", "");
|
||||
store.add({ hello: "world" }, 42);
|
||||
trans.oncomplete = function() {
|
||||
parent.postMessage("go", "http://mochi.test:8888");
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
This is page one.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var res = {};
|
||||
moz_indexedDB.open(parent.location).onsuccess = function(e) {
|
||||
var db = e.result;
|
||||
res.version = db.version;
|
||||
res.storeCount = db.objectStoreNames.length;
|
||||
|
||||
req = db.setVersion("2.0");
|
||||
req.onblocked = function() {
|
||||
res.blockedFired = true;
|
||||
}
|
||||
req.onsuccess = function(e) {
|
||||
var trans = e.transaction;
|
||||
trans.objectStore("mystore").get(42).onsuccess = function(e) {
|
||||
res.value = JSON.stringify(e.result);
|
||||
}
|
||||
trans.oncomplete = function() {
|
||||
parent.postMessage(JSON.stringify(res), "http://mochi.test:8888");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
This is page two.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property 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"/>
|
||||
<script type="text/javascript;version=1.7">
|
||||
var gOrigMaxTotalViewers = undefined;
|
||||
function setCachePref(enabled) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
if (enabled) {
|
||||
is(typeof gOrigMaxTotalViewers, "undefined", "don't double-enable bfcache");
|
||||
prefBranch.setBoolPref("browser.sessionhistory.cache_subframes", true);
|
||||
gOrigMaxTotalViewers = prefBranch.getIntPref("browser.sessionhistory.max_total_viewers");
|
||||
prefBranch.setIntPref("browser.sessionhistory.max_total_viewers", 10);
|
||||
}
|
||||
else {
|
||||
is(typeof gOrigMaxTotalViewers, "number", "don't double-disable bfcache");
|
||||
prefBranch.setIntPref("browser.sessionhistory.max_total_viewers", gOrigMaxTotalViewers);
|
||||
gOrigMaxTotalViewers = undefined;
|
||||
try {
|
||||
prefBranch.clearUserPref("browser.sessionhistory.cache_subframes");
|
||||
} catch (e) { /* Pref didn't exist, meh */ }
|
||||
}
|
||||
}
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
var iframe = $("iframe");
|
||||
setCachePref(true);
|
||||
window.onmessage = grabEventAndContinueHandler;
|
||||
|
||||
iframe.src = "bfcache_iframe1.html";
|
||||
var event = yield;
|
||||
is(event.data, "go", "set up database successfully");
|
||||
|
||||
iframe.src = "bfcache_iframe2.html";
|
||||
res = JSON.parse((yield).data);
|
||||
is(res.version, "1.0", "version was set correctly");
|
||||
is(res.storeCount, 1, "correct set of stores");
|
||||
ok(!("blockedFired" in res), "blocked shouldn't fire");
|
||||
is(res.value, JSON.stringify({ hello: "world" }),
|
||||
"correct value found in store");
|
||||
|
||||
setCachePref(false);
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<iframe id="iframe"></iframe>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1539,6 +1539,7 @@ DocumentViewerImpl::Destroy()
|
|||
nsresult rv = mDocument->Sanitize();
|
||||
if (NS_FAILED(rv)) {
|
||||
// If we failed to sanitize, don't save presentation.
|
||||
// XXX Shouldn't we run all the stuff after the |if (mSHEntry)| then?
|
||||
savePresentation = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -1560,8 +1561,9 @@ DocumentViewerImpl::Destroy()
|
|||
// When the presentation is restored, Open() and InitInternal() will reset
|
||||
// these pointers to their original values.
|
||||
|
||||
if (mDocument)
|
||||
if (mDocument) {
|
||||
mDocument->SetContainer(nsnull);
|
||||
}
|
||||
if (mPresContext) {
|
||||
mPresContext->SetLinkHandler(nsnull);
|
||||
mPresContext->SetContainer(nsnull);
|
||||
|
@ -1581,6 +1583,8 @@ DocumentViewerImpl::Destroy()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// The document was not put in the bfcache
|
||||
|
||||
if (mDocument) {
|
||||
mDocument->Destroy();
|
||||
mDocument = nsnull;
|
||||
|
|
Загрузка…
Ссылка в новой задаче