mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Bug 395045. Expire cached content-viewers after they've been unused for 20-30 minutes. r+sr+a=bz
This commit is contained in:
parent
3febe0fecf
commit
438effcc42
@ -80,12 +80,16 @@ Initialize(nsIModule* aSelf)
|
||||
gInitialized = PR_TRUE;
|
||||
|
||||
nsresult rv = nsSHistory::Startup();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsSHEntry::Startup();
|
||||
return rv;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
Shutdown(nsIModule* aSelf)
|
||||
{
|
||||
nsSHEntry::Shutdown();
|
||||
gInitialized = PR_FALSE;
|
||||
}
|
||||
|
||||
|
@ -46,12 +46,13 @@ interface nsIDocShell;
|
||||
|
||||
%{C++
|
||||
#define NS_SHISTORY_INTERNAL_CID \
|
||||
{0x5b4cba4c, 0xbf67, 0x499a, {0xae, 0x2c, 0x3f, 0x76, 0x65, 0x6f, 0x4a, 0x4e}}
|
||||
{ 0x9c47c121, 0x1c6e, 0x4d8f, \
|
||||
{ 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
|
||||
|
||||
#define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
|
||||
%}
|
||||
|
||||
[scriptable, uuid(df8788d6-c0ed-4517-b47e-c719afc94284)]
|
||||
[scriptable, uuid(9c47c121-1c6e-4d8f-b904-3ac968116e88)]
|
||||
interface nsISHistoryInternal: nsISupports
|
||||
{
|
||||
/**
|
||||
@ -98,4 +99,10 @@ interface nsISHistoryInternal: nsISupports
|
||||
* the previous viewer.
|
||||
*/
|
||||
void evictContentViewers(in long previousIndex, in long index);
|
||||
|
||||
/**
|
||||
* Evict the content viewer associated with a session history entry
|
||||
* that has timed out.
|
||||
*/
|
||||
void evictExpiredContentViewerForEntry(in nsISHEntry aEntry);
|
||||
};
|
||||
|
@ -51,14 +51,53 @@
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHistoryInternal.h"
|
||||
|
||||
// Hardcode this to time out unused content viewers after 30 minutes
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS 30*60
|
||||
|
||||
typedef nsExpirationTracker<nsSHEntry,3> HistoryTrackerBase;
|
||||
class HistoryTracker : public HistoryTrackerBase {
|
||||
public:
|
||||
// Expire cached contentviewers after 20-30 minutes in the cache.
|
||||
HistoryTracker() : HistoryTrackerBase((CONTENT_VIEWER_TIMEOUT_SECONDS/2)*1000) {}
|
||||
|
||||
protected:
|
||||
virtual void NotifyExpired(nsSHEntry* aObj) {
|
||||
RemoveObject(aObj);
|
||||
aObj->Expire();
|
||||
}
|
||||
};
|
||||
|
||||
static HistoryTracker *gHistoryTracker = nsnull;
|
||||
static PRUint32 gEntryID = 0;
|
||||
|
||||
nsresult nsSHEntry::Startup()
|
||||
{
|
||||
gHistoryTracker = new HistoryTracker();
|
||||
return gHistoryTracker ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
void nsSHEntry::Shutdown()
|
||||
{
|
||||
delete gHistoryTracker;
|
||||
gHistoryTracker = nsnull;
|
||||
}
|
||||
|
||||
static void StopTrackingEntry(nsSHEntry *aEntry)
|
||||
{
|
||||
if (aEntry->GetExpirationState()->IsTracked()) {
|
||||
gHistoryTracker->RemoveObject(aEntry);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//*** nsSHEntry: Object Management
|
||||
//*****************************************************************************
|
||||
|
||||
|
||||
nsSHEntry::nsSHEntry()
|
||||
: mLoadType(0)
|
||||
, mID(gEntryID++)
|
||||
@ -109,6 +148,8 @@ ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
|
||||
|
||||
nsSHEntry::~nsSHEntry()
|
||||
{
|
||||
StopTrackingEntry(this);
|
||||
|
||||
// Since we never really remove kids from SHEntrys, we need to null
|
||||
// out the mParent pointers on all our kids.
|
||||
mChildren.EnumerateForwards(ClearParentPtr, nsnull);
|
||||
@ -193,6 +234,8 @@ nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
|
||||
mDocument->SetShellsHidden(PR_TRUE);
|
||||
mDocument->AddMutationObserver(this);
|
||||
}
|
||||
|
||||
gHistoryTracker->AddObject(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -637,6 +680,7 @@ nsSHEntry::DropPresentationState()
|
||||
if (mContentViewer)
|
||||
mContentViewer->ClearHistoryEntry();
|
||||
|
||||
StopTrackingEntry(this);
|
||||
mContentViewer = nsnull;
|
||||
mSticky = PR_TRUE;
|
||||
mWindowState = nsnull;
|
||||
@ -645,6 +689,31 @@ nsSHEntry::DropPresentationState()
|
||||
mRefreshURIList = nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntry::Expire()
|
||||
{
|
||||
// This entry has timed out. If we still have a content viewer, we need to
|
||||
// get it evicted.
|
||||
if (!mContentViewer)
|
||||
return;
|
||||
nsCOMPtr<nsISupports> container;
|
||||
mContentViewer->GetContainer(getter_AddRefs(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
|
||||
if (!treeItem)
|
||||
return;
|
||||
// We need to find the root DocShell since only that object has an
|
||||
// SHistory and we need the SHistory to evict content viewers
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
|
||||
nsCOMPtr<nsISHistory> history;
|
||||
webNav->GetSessionHistory(getter_AddRefs(history));
|
||||
nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
|
||||
if (!historyInt)
|
||||
return;
|
||||
historyInt->EvictExpiredContentViewerForEntry(this);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsSHEntry: nsIMutationObserver
|
||||
//*****************************************************************************
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "nsRect.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
|
||||
class nsSHEntry : public nsISHEntry,
|
||||
public nsISHContainer,
|
||||
@ -75,6 +76,13 @@ public:
|
||||
|
||||
void DropPresentationState();
|
||||
|
||||
void Expire();
|
||||
|
||||
nsExpirationState *GetExpirationState() { return &mExpirationState; }
|
||||
|
||||
static nsresult Startup();
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
~nsSHEntry();
|
||||
void DocumentMutated();
|
||||
@ -104,6 +112,7 @@ private:
|
||||
nsCOMArray<nsIDocShellTreeItem> mChildShells;
|
||||
nsCOMPtr<nsISupportsArray> mRefreshURIList;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsExpirationState mExpirationState;
|
||||
};
|
||||
|
||||
#endif /* nsSHEntry_h */
|
||||
|
@ -790,10 +790,16 @@ nsSHistory::EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex)
|
||||
endIndex = PR_MIN(mLength, aFromIndex + gHistoryMaxViewers);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISHTransaction> trans;
|
||||
GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
|
||||
EvictContentViewersInRange(startIndex, endIndex);
|
||||
}
|
||||
|
||||
for (PRInt32 i = startIndex; i < endIndex; ++i) {
|
||||
void
|
||||
nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd)
|
||||
{
|
||||
nsCOMPtr<nsISHTransaction> trans;
|
||||
GetTransactionAtIndex(aStart, getter_AddRefs(trans));
|
||||
|
||||
for (PRInt32 i = aStart; i < aEnd; ++i) {
|
||||
nsCOMPtr<nsISHEntry> entry;
|
||||
trans->GetSHEntry(getter_AddRefs(entry));
|
||||
nsCOMPtr<nsIContentViewer> viewer;
|
||||
@ -941,6 +947,46 @@ nsSHistory::EvictGlobalContentViewer()
|
||||
} // while shouldTryEviction
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
|
||||
{
|
||||
PRInt32 startIndex = PR_MAX(0, mIndex - gHistoryMaxViewers);
|
||||
PRInt32 endIndex = PR_MIN(mLength - 1,
|
||||
mIndex + gHistoryMaxViewers);
|
||||
nsCOMPtr<nsISHTransaction> trans;
|
||||
GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
|
||||
|
||||
PRInt32 i;
|
||||
for (i = startIndex; i <= endIndex; ++i) {
|
||||
nsCOMPtr<nsISHEntry> entry;
|
||||
trans->GetSHEntry(getter_AddRefs(entry));
|
||||
if (entry == aEntry)
|
||||
break;
|
||||
|
||||
nsISHTransaction *temp = trans;
|
||||
temp->GetNext(getter_AddRefs(trans));
|
||||
}
|
||||
if (i > endIndex)
|
||||
return NS_OK;
|
||||
|
||||
NS_ASSERTION(i != mIndex, "How did the current session entry expire?");
|
||||
if (i == mIndex)
|
||||
return NS_OK;
|
||||
|
||||
// We evict content viewers for the expired entry and any other entries that
|
||||
// we would have to go through the expired entry to get to (i.e. the entries
|
||||
// that have the expired entry between them and the current entry). Those
|
||||
// other entries should have timed out already, actually, but this is just
|
||||
// to be on the safe side.
|
||||
if (i < mIndex) {
|
||||
EvictContentViewersInRange(startIndex, i + 1);
|
||||
} else {
|
||||
EvictContentViewersInRange(i, endIndex + 1);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Evicts all content viewers in all history objects. This is very
|
||||
// inefficient, because it requires a linear search through all SHistory
|
||||
// objects for each viewer to be evicted. However, this method is called
|
||||
|
@ -99,6 +99,7 @@ protected:
|
||||
nsresult PrintHistory();
|
||||
#endif
|
||||
|
||||
void EvictContentViewersInRange(PRInt32 aStartIndex, PRInt32 aEndIndex);
|
||||
void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
|
||||
static void EvictGlobalContentViewer();
|
||||
static void EvictAllContentViewers();
|
||||
|
Loading…
Reference in New Issue
Block a user