зеркало из https://github.com/mozilla/pjs.git
Bug 329816 r=bryner Make time-critical history operations lazy to improve PLT.
This commit is contained in:
Родитель
17dd36d156
Коммит
504f1732ad
|
@ -389,6 +389,23 @@ nsFaviconService::SendFaviconNotifications(nsIURI* aPage, nsIURI* aFaviconURI)
|
|||
NS_IMETHODIMP
|
||||
nsFaviconService::SetAndLoadFaviconForPage(nsIURI* aPage, nsIURI* aFavicon,
|
||||
PRBool aForceReload)
|
||||
{
|
||||
#ifdef LAZY_ADD
|
||||
nsNavHistory* historyService = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY);
|
||||
return historyService->AddLazyLoadFaviconMessage(aPage, aFavicon,
|
||||
aForceReload);
|
||||
#else
|
||||
return DoSetAndLoadFaviconForPage(aPage, aFavicon, aForceReload);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// nsFaviconService::DoSetAndLoadFaviconForPage
|
||||
|
||||
nsresult
|
||||
nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPage, nsIURI* aFavicon,
|
||||
PRBool aForceReload)
|
||||
{
|
||||
// check the failed favicon cache
|
||||
PRBool previouslyFailed;
|
||||
|
|
|
@ -82,6 +82,10 @@ public:
|
|||
return gFaviconService;
|
||||
}
|
||||
|
||||
// internal version called by history when done lazily
|
||||
nsresult DoSetAndLoadFaviconForPage(nsIURI* aPage, nsIURI* aFavicon,
|
||||
PRBool aForceReload);
|
||||
|
||||
// addition to API for strings to prevent excessive parsing of URIs
|
||||
nsresult GetFaviconLinkForIconString(const nsCString& aIcon, nsIURI** aOutput);
|
||||
void GetFaviconSpecForIconString(const nsCString& aIcon, nsACString& aOutput);
|
||||
|
|
|
@ -1554,6 +1554,10 @@ nsNavBookmarks::SetItemTitle(nsIURI *aURI, const nsAString &aTitle)
|
|||
NS_IMETHODIMP
|
||||
nsNavBookmarks::GetItemTitle(nsIURI *aURI, nsAString &aTitle)
|
||||
{
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||
history->SyncDB();
|
||||
|
||||
mozIStorageStatement *statement = DBGetURLPageInfo();
|
||||
nsresult rv = BindStatementURI(statement, 0, aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -108,6 +108,19 @@
|
|||
#define HISTORY_URI_LENGTH_MAX 65536
|
||||
#define HISTORY_TITLE_LENGTH_MAX 4096
|
||||
|
||||
// Lazy adding
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
|
||||
// time that we'll wait before committing messages
|
||||
#define LAZY_MESSAGE_TIMEOUT (3 * PR_MSEC_PER_SEC)
|
||||
|
||||
// the maximum number of times we'll postpone a lazy timer before committing
|
||||
// See StartLazyTimer()
|
||||
#define MAX_LAZY_TIMER_DEFERMENTS 2
|
||||
|
||||
#endif // LAZY_ADD
|
||||
|
||||
NS_IMPL_ADDREF(nsNavHistory)
|
||||
NS_IMPL_RELEASE(nsNavHistory)
|
||||
|
||||
|
@ -205,6 +218,10 @@ nsNavHistory::nsNavHistory() : mNowValid(PR_FALSE),
|
|||
mExpireNowTimer(nsnull),
|
||||
mBatchesInProgress(0)
|
||||
{
|
||||
#ifdef LAZY_ADD
|
||||
mLazyTimerSet = PR_TRUE;
|
||||
mLazyTimerDeferments = 0;
|
||||
#endif
|
||||
NS_ASSERTION(! gHistoryService, "YOU ARE CREATING 2 COPIES OF THE HISTORY SERVICE. Everything will break.");
|
||||
gHistoryService = this;
|
||||
|
||||
|
@ -952,6 +969,17 @@ PRBool nsNavHistory::IsURIStringVisited(const nsACString& aURIString)
|
|||
mMemDBGetPage->Reset();
|
||||
return hasPage;
|
||||
#else
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
// check the lazy list to see if this has recently been added
|
||||
for (PRUint32 i = 0; i < mLazyMessages.Length(); i ++) {
|
||||
if (mLazyMessages[i].type == LazyMessage::Type_AddURI) {
|
||||
if (aURIString.Equals(mLazyMessages[i].uriSpec))
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// check the main DB
|
||||
nsresult rv;
|
||||
mozStorageStatementScoper statementResetter(mDBGetURLPageInfo);
|
||||
|
@ -1123,8 +1151,7 @@ nsNavHistory::GetNow()
|
|||
|
||||
// nsNavHistory::expireNowTimerCallback
|
||||
|
||||
void nsNavHistory::expireNowTimerCallback(nsITimer* aTimer,
|
||||
void* aClosure)
|
||||
void nsNavHistory::expireNowTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsNavHistory* history = NS_STATIC_CAST(nsNavHistory*, aClosure);
|
||||
history->mNowValid = PR_FALSE;
|
||||
|
@ -2497,11 +2524,37 @@ nsNavHistory::AddURI(nsIURI *aURI, PRBool aRedirect,
|
|||
if (mExpireDays == 0)
|
||||
return NS_OK;
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
LazyMessage message;
|
||||
nsresult rv = message.Init(LazyMessage::Type_AddURI, aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
message.isRedirect = aRedirect;
|
||||
message.isToplevel = aToplevel;
|
||||
if (aReferrer) {
|
||||
rv = aReferrer->Clone(getter_AddRefs(message.referrer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
message.time = PR_Now();
|
||||
return AddLazyMessage(message);
|
||||
#else
|
||||
return AddURIInternal(aURI, PR_Now(), aRedirect, aToplevel, aReferrer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::AddURIInternal
|
||||
//
|
||||
// This does the work of AddURI so it can be done lazily.
|
||||
|
||||
nsresult
|
||||
nsNavHistory::AddURIInternal(nsIURI* aURI, PRTime aTime, PRBool aRedirect,
|
||||
PRBool aToplevel, nsIURI* aReferrer)
|
||||
{
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
PRInt64 redirectBookmark = 0;
|
||||
PRInt64 visitID, sessionID;
|
||||
nsresult rv = AddVisitChain(aURI, aToplevel, aRedirect, aReferrer,
|
||||
nsresult rv = AddVisitChain(aURI, aTime, aToplevel, aRedirect, aReferrer,
|
||||
&visitID, &sessionID, &redirectBookmark);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -2548,7 +2601,8 @@ nsNavHistory::AddURI(nsIURI *aURI, PRBool aRedirect,
|
|||
// hashtable.
|
||||
|
||||
nsresult
|
||||
nsNavHistory::AddVisitChain(nsIURI* aURI, PRBool aToplevel, PRBool aIsRedirect,
|
||||
nsNavHistory::AddVisitChain(nsIURI* aURI, PRTime aTime,
|
||||
PRBool aToplevel, PRBool aIsRedirect,
|
||||
nsIURI* aReferrer, PRInt64* aVisitID,
|
||||
PRInt64* aSessionID, PRInt64* aRedirectBookmark)
|
||||
{
|
||||
|
@ -2576,8 +2630,12 @@ nsNavHistory::AddVisitChain(nsIURI* aURI, PRBool aToplevel, PRBool aIsRedirect,
|
|||
GetUrlIdFor(redirectURI, aRedirectBookmark, PR_FALSE);
|
||||
}
|
||||
|
||||
// Find the visit for the source
|
||||
rv = AddVisitChain(redirectURI, aToplevel, PR_TRUE, aReferrer,
|
||||
// Find the visit for the source. Note that we decrease the time counter,
|
||||
// which will ensure that the referrer and this page will appear in history
|
||||
// in the correct order. Since the times are in microseconds, it should not
|
||||
// normally be possible to get two pages within one microsecond of each
|
||||
// other so the referrer won't appear before a previous page viewed.
|
||||
rv = AddVisitChain(redirectURI, aTime - 1, aToplevel, PR_TRUE, aReferrer,
|
||||
&referringVisit, aSessionID, aRedirectBookmark);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -2676,7 +2734,16 @@ nsNavHistory::SetPageTitle(nsIURI *aURI,
|
|||
{
|
||||
if (aTitle.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
LazyMessage message;
|
||||
nsresult rv = message.Init(LazyMessage::Type_Title, aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
message.title = aTitle;
|
||||
return AddLazyMessage(message);
|
||||
#else
|
||||
return SetPageTitleInternal(aURI, PR_FALSE, aTitle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -2813,6 +2880,123 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Lazy stuff ******************************************************************
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
|
||||
// nsNavHistory::AddLazyLoadFaviconMessage
|
||||
|
||||
nsresult
|
||||
nsNavHistory::AddLazyLoadFaviconMessage(nsIURI* aPage, nsIURI* aFavicon,
|
||||
PRBool aForceReload)
|
||||
{
|
||||
LazyMessage message;
|
||||
nsresult rv = message.Init(LazyMessage::Type_Favicon, aPage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aFavicon->Clone(getter_AddRefs(message.favicon));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
message.alwaysLoadFavicon = aForceReload;
|
||||
return AddLazyMessage(message);
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::StartLazyTimer
|
||||
//
|
||||
// This schedules flushing of the lazy message queue for the future.
|
||||
//
|
||||
// If we already have timer set, we canel it and schedule a new timer in
|
||||
// the future. This saves you from having to wait if you open a bunch of
|
||||
// pages in a row. However, we don't want to defer too long, so we'll only
|
||||
// push it back MAX_LAZY_TIMER_DEFERMENTS times. After that we always
|
||||
// let the timer go the next time.
|
||||
|
||||
nsresult
|
||||
nsNavHistory::StartLazyTimer()
|
||||
{
|
||||
if (! mLazyTimer) {
|
||||
mLazyTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (! mLazyTimer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
if (mLazyTimerSet) {
|
||||
if (mLazyTimerDeferments >= MAX_LAZY_TIMER_DEFERMENTS) {
|
||||
// already set and we don't want to push it back any later, use that one
|
||||
return NS_OK;
|
||||
} else {
|
||||
// push back the active timer
|
||||
mLazyTimer->Cancel();
|
||||
mLazyTimerDeferments ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
nsresult rv = mLazyTimer->InitWithFuncCallback(LazyTimerCallback, this,
|
||||
LAZY_MESSAGE_TIMEOUT,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mLazyTimerSet = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::AddLazyMessage
|
||||
|
||||
nsresult
|
||||
nsNavHistory::AddLazyMessage(const LazyMessage& aMessage)
|
||||
{
|
||||
if (! mLazyMessages.AppendElement(aMessage))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return StartLazyTimer();
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::LazyTimerCallback
|
||||
|
||||
void // static
|
||||
nsNavHistory::LazyTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsNavHistory* that = NS_STATIC_CAST(nsNavHistory*, aClosure);
|
||||
that->mLazyTimerSet = PR_FALSE;
|
||||
that->mLazyTimerDeferments = 0;
|
||||
that->CommitLazyMessages();
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::CommitLazyMessages
|
||||
|
||||
void
|
||||
nsNavHistory::CommitLazyMessages()
|
||||
{
|
||||
for (PRUint32 i = 0; i < mLazyMessages.Length(); i ++) {
|
||||
LazyMessage& message = mLazyMessages[i];
|
||||
switch (message.type) {
|
||||
case LazyMessage::Type_AddURI:
|
||||
AddURIInternal(message.uri, message.time, message.isRedirect,
|
||||
message.isToplevel, message.referrer);
|
||||
break;
|
||||
case LazyMessage::Type_Title:
|
||||
SetPageTitleInternal(message.uri, PR_FALSE, message.title);
|
||||
break;
|
||||
case LazyMessage::Type_Favicon: {
|
||||
nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
|
||||
if (faviconService) {
|
||||
nsCString spec;
|
||||
message.uri->GetSpec(spec);
|
||||
faviconService->DoSetAndLoadFaviconForPage(message.uri,
|
||||
message.favicon,
|
||||
message.alwaysLoadFavicon);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_NOTREACHED("Invalid lazy message type");
|
||||
}
|
||||
}
|
||||
mLazyMessages.Clear();
|
||||
}
|
||||
#endif // LAZY_ADD
|
||||
|
||||
|
||||
// Query stuff *****************************************************************
|
||||
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
// set to use more optimized (in-memory database) link coloring
|
||||
//#define IN_MEMORY_LINKS
|
||||
|
||||
// define to enable lazy link adding
|
||||
#define LAZY_ADD
|
||||
|
||||
#define QUERYUPDATE_TIME 0
|
||||
#define QUERYUPDATE_SIMPLE 1
|
||||
#define QUERYUPDATE_COMPLEX 2
|
||||
|
@ -135,6 +138,30 @@ public:
|
|||
return gHistoryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function before doing any database reads. It will ensure that
|
||||
* any data not flushed to the DB yet is flushed.
|
||||
*/
|
||||
void SyncDB()
|
||||
{
|
||||
#ifdef LAZY_ADD
|
||||
CommitLazyMessages();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
/**
|
||||
* Adds a lazy message for adding a favicon. Used by the favicon service so
|
||||
* that favicons are handled lazily just like page adds.
|
||||
*/
|
||||
nsresult AddLazyLoadFaviconMessage(nsIURI* aPage, nsIURI* aFavicon,
|
||||
PRBool aForceReload);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the database ID for the given URI, or 0 if not found an autoCreate
|
||||
* is false.
|
||||
*/
|
||||
nsresult GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
|
||||
PRBool aAutoCreate);
|
||||
|
||||
|
@ -351,7 +378,11 @@ protected:
|
|||
nsCOMPtr<mozIStorageConnection> mDummyDBConn;
|
||||
nsCOMPtr<mozIStorageStatement> mDBDummyStatement;
|
||||
|
||||
nsresult AddVisitChain(nsIURI* aURI, PRBool aToplevel, PRBool aRedirect,
|
||||
nsresult AddURIInternal(nsIURI* aURI, PRTime aTime, PRBool aRedirect,
|
||||
PRBool aToplevel, nsIURI* aReferrer);
|
||||
|
||||
nsresult AddVisitChain(nsIURI* aURI, PRTime aTime,
|
||||
PRBool aToplevel, PRBool aRedirect,
|
||||
nsIURI* aReferrer, PRInt64* aVisitID,
|
||||
PRInt64* aSessionID, PRInt64* aRedirectBookmark);
|
||||
nsresult InternalAddNewPage(nsIURI* aURI, const nsAString& aTitle,
|
||||
|
@ -372,6 +403,57 @@ protected:
|
|||
nsCOMPtr<nsITimer> mExpireNowTimer;
|
||||
static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
// lazy add committing
|
||||
struct LazyMessage {
|
||||
enum MessageType { Type_Invalid, Type_AddURI, Type_Title, Type_Favicon };
|
||||
LazyMessage()
|
||||
{
|
||||
type = Type_Invalid;
|
||||
isRedirect = PR_FALSE;
|
||||
isToplevel = PR_FALSE;
|
||||
time = 0;
|
||||
alwaysLoadFavicon = PR_FALSE;
|
||||
}
|
||||
|
||||
// call this with common parms to initialize. Caller is responsible for
|
||||
// setting other elements manually depending on type.
|
||||
nsresult Init(MessageType aType, nsIURI* aURI)
|
||||
{
|
||||
type = aType;
|
||||
nsresult rv = aURI->Clone(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return uri->GetSpec(uriSpec);
|
||||
}
|
||||
|
||||
// common elements
|
||||
MessageType type;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCString uriSpec; // stringified version of URI, for quick isVisited
|
||||
|
||||
// valid when type == Type_AddURI
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
PRBool isRedirect;
|
||||
PRBool isToplevel;
|
||||
PRTime time;
|
||||
|
||||
// valid when type == Type_Title
|
||||
nsString title;
|
||||
|
||||
// valid when type == LAZY_FAVICON
|
||||
nsCOMPtr<nsIURI> favicon;
|
||||
PRBool alwaysLoadFavicon;
|
||||
};
|
||||
nsTArray<LazyMessage> mLazyMessages;
|
||||
nsCOMPtr<nsITimer> mLazyTimer;
|
||||
PRBool mLazyTimerSet;
|
||||
PRUint32 mLazyTimerDeferments; // see StartLazyTimer
|
||||
nsresult StartLazyTimer();
|
||||
nsresult AddLazyMessage(const LazyMessage& aMessage);
|
||||
static void LazyTimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
void CommitLazyMessages();
|
||||
#endif
|
||||
|
||||
nsresult QueryToSelectClause(nsNavHistoryQuery* aQuery,
|
||||
PRInt32 aStartParameter,
|
||||
nsCString* aClause,
|
||||
|
|
Загрузка…
Ссылка в новой задаче