diff --git a/mailnews/base/src/nsMsgThreadedDBView.cpp b/mailnews/base/src/nsMsgThreadedDBView.cpp index fc3e26cd435b..0e1c44ad219f 100644 --- a/mailnews/base/src/nsMsgThreadedDBView.cpp +++ b/mailnews/base/src/nsMsgThreadedDBView.cpp @@ -39,6 +39,10 @@ #include "nsMsgThreadedDBView.h" #include "nsIMsgHdr.h" #include "nsIMsgThread.h" +#include "nsIDBFolderInfo.h" + +#define MSGHDR_CACHE_LOOK_AHEAD_SIZE 25 // Allocate this more to avoid reallocation on new mail. +#define MSGHDR_CACHE_MAX_SIZE 8192 // Max msghdr cache entries. nsMsgThreadedDBView::nsMsgThreadedDBView() { @@ -57,6 +61,30 @@ NS_IMETHODIMP nsMsgThreadedDBView::Open(nsIMsgFolder *folder, nsMsgViewSortTypeV rv = nsMsgDBView::Open(folder, sortType, sortOrder, viewFlags, pCount); NS_ENSURE_SUCCESS(rv, rv); + // Preset msg hdr cache size for performance reason. + if (m_db) + { + PRInt32 totalMessages, unreadMessages; + nsCOMPtr dbFolderInfo; + rv = m_db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo)); + NS_ENSURE_SUCCESS(rv, rv); + if (m_viewFlags & nsMsgViewFlagsType::kUnreadOnly) + { + // Set unread msg size + extra entries to avoid reallocation on new mail. + dbFolderInfo->GetNumNewMessages(&unreadMessages); + totalMessages = (PRUint32)unreadMessages+MSGHDR_CACHE_LOOK_AHEAD_SIZE; + } + else + { + dbFolderInfo->GetNumMessages(&totalMessages); + if (totalMessages > MSGHDR_CACHE_MAX_SIZE) + totalMessages = MSGHDR_CACHE_MAX_SIZE; // use max default + else + totalMessages += MSGHDR_CACHE_LOOK_AHEAD_SIZE;// allocate extra entries to avoid reallocation on new mail. + } + m_db->SetMsgHdrCacheSize((PRUint32)totalMessages); + } + if (pCount) *pCount = 0; return InitThreadedView(pCount); @@ -137,6 +165,10 @@ nsresult nsMsgThreadedDBView::AddKeys(nsMsgKey *pKeys, PRInt32 *pFlags, const ch { PRInt32 numAdded = 0; + // Allocate enough space first to avoid memory allocation/deallocation. + m_keys.AllocateSpace(numKeysToAdd); + m_flags.AllocateSpace(numKeysToAdd); + m_levels.AllocateSpace(numKeysToAdd); for (PRInt32 i = 0; i < numKeysToAdd; i++) { PRInt32 threadFlag = pFlags[i]; diff --git a/mailnews/base/util/nsUInt32Array.cpp b/mailnews/base/util/nsUInt32Array.cpp index 75773edf8cde..f131537dbed7 100644 --- a/mailnews/base/util/nsUInt32Array.cpp +++ b/mailnews/base/util/nsUInt32Array.cpp @@ -92,10 +92,10 @@ PRBool nsUInt32Array::SetSize(PRUint32 nSize, } else if (nSize <= m_nMaxSize) { - // The new size is within the current maximum size, make sure new - // elements are to initialized to zero - if (nSize > m_nSize) - nsCRT::memset(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(PRUint32)); + // The new size is within the current maximum size, make sure new + // elements are to initialized to zero + if (nSize > m_nSize) + nsCRT::memset(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(PRUint32)); m_nSize = nSize; } diff --git a/mailnews/base/util/nsUInt32Array.h b/mailnews/base/util/nsUInt32Array.h index f8fa33405466..7e8930bafa5b 100644 --- a/mailnews/base/util/nsUInt32Array.h +++ b/mailnews/base/util/nsUInt32Array.h @@ -43,6 +43,12 @@ public: // State/attribute member functions PRUint32 GetSize() const; PRBool SetSize(PRUint32 nNewSize, PRBool AdjustGrowth=PR_FALSE, PRUint32 nGrowBy = 0); + PRBool AllocateSpace(PRUint32 nNewSize) { + PRUint32 saveSize = m_nSize; + nsresult rv = SetSize(nNewSize); + m_nSize = saveSize; + return rv; + }; // Accessor member functions PRUint32 &ElementAt(PRUint32 nIndex); diff --git a/mailnews/base/util/nsUint8Array.cpp b/mailnews/base/util/nsUint8Array.cpp index 2df08f5118dd..7cd6a30c3f09 100644 --- a/mailnews/base/util/nsUint8Array.cpp +++ b/mailnews/base/util/nsUint8Array.cpp @@ -77,14 +77,14 @@ void nsUint8Array::SetSize(PRInt32 nNewSize, PRInt32 nGrowBy) } else if (nNewSize <= m_nMaxSize) { - // it fits - if (nNewSize > m_nSize) - { - // initialize the new elements + // it fits + if (nNewSize > m_nSize) + { + // initialize the new elements nsCRT::memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(PRUint8)); - } + } m_nSize = nNewSize; } diff --git a/mailnews/base/util/nsUint8Array.h b/mailnews/base/util/nsUint8Array.h index d06f3feed4fd..291453c7a175 100644 --- a/mailnews/base/util/nsUint8Array.h +++ b/mailnews/base/util/nsUint8Array.h @@ -20,6 +20,7 @@ public: PRInt32 GetSize() const; PRInt32 GetUpperBound() const; void SetSize(PRInt32 nNewSize, PRInt32 nGrowBy = -1); + void AllocateSpace(PRUint32 nNewSize) { PRInt32 saveSize = m_nSize; SetSize(nNewSize); m_nSize = saveSize;}; // Operations // Clean up diff --git a/mailnews/db/msgdb/public/nsDBFolderInfo.h b/mailnews/db/msgdb/public/nsDBFolderInfo.h index 7929023d221f..10692a1a83dd 100644 --- a/mailnews/db/msgdb/public/nsDBFolderInfo.h +++ b/mailnews/db/msgdb/public/nsDBFolderInfo.h @@ -106,9 +106,11 @@ protected: time_t m_folderDate; nsMsgKey m_highWaterMessageKey; // largest news article number or imap uid whose header we've seen + // m_numVisibleMessages, m_numNewMessages and m_numMessages can never be negative. 0 means 'no msgs'. PRInt32 m_numVisibleMessages; // doesn't include expunged or ignored messages (but does include collapsed). PRInt32 m_numNewMessages; PRInt32 m_numMessages; // includes expunged and ignored messages + PRInt32 m_flags; // folder specific flags. This holds things like re-use thread pane, // configured for off-line use, use default retrieval, purge article/header options nsMsgKey m_lastMessageLoaded; // set by the FE's to remember the last loaded message diff --git a/mailnews/db/msgdb/public/nsIDBFolderInfo.idl b/mailnews/db/msgdb/public/nsIDBFolderInfo.idl index 01957e5f53a6..ae205805b969 100644 --- a/mailnews/db/msgdb/public/nsIDBFolderInfo.idl +++ b/mailnews/db/msgdb/public/nsIDBFolderInfo.idl @@ -57,6 +57,8 @@ interface nsIDBFolderInfo : nsISupports { attribute unsigned long FolderDate; void ChangeNumNewMessages(in long delta); void ChangeNumMessages(in long delta); + + // ChangeNumVisibleMessages, NumNewMessages and NumMessages will never return negative numbers. 0 means 'no msgs'. void ChangeNumVisibleMessages(in long delta); attribute long NumNewMessages; attribute long NumMessages; diff --git a/mailnews/db/msgdb/public/nsIMsgDatabase.idl b/mailnews/db/msgdb/public/nsIMsgDatabase.idl index a8b5ce76728f..6f20ebe17c2a 100644 --- a/mailnews/db/msgdb/public/nsIMsgDatabase.idl +++ b/mailnews/db/msgdb/public/nsIMsgDatabase.idl @@ -264,5 +264,8 @@ interface nsIMsgDatabase : nsIDBChangeAnnouncer { // news can be threaded by default) readonly attribute nsMsgViewFlagsTypeValue defaultViewFlags; readonly attribute nsMsgViewSortTypeValue defaultSortType; + + // for msg hdr hash table allocation. controllable by caller to improve folder loading preformance. + attribute unsigned long msgHdrCacheSize; }; diff --git a/mailnews/db/msgdb/public/nsMsgDatabase.h b/mailnews/db/msgdb/public/nsMsgDatabase.h index f5c9f9742107..2e81eae363ce 100644 --- a/mailnews/db/msgdb/public/nsMsgDatabase.h +++ b/mailnews/db/msgdb/public/nsMsgDatabase.h @@ -283,6 +283,8 @@ virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr); PLDHashTable *m_cachedHeaders; PRBool m_bCacheHeaders; +private: + PRUint32 m_cacheSize; }; class nsMsgRetentionSettings : public nsIMsgRetentionSettings diff --git a/mailnews/db/msgdb/src/nsDBFolderInfo.cpp b/mailnews/db/msgdb/src/nsDBFolderInfo.cpp index 259dc855524c..369cd155d782 100644 --- a/mailnews/db/msgdb/src/nsDBFolderInfo.cpp +++ b/mailnews/db/msgdb/src/nsDBFolderInfo.cpp @@ -522,6 +522,7 @@ NS_IMETHODIMP nsDBFolderInfo::GetMailboxName(nsString *boxName) NS_IMETHODIMP nsDBFolderInfo::ChangeNumNewMessages(PRInt32 delta) { m_numNewMessages += delta; + // m_numNewMessages can never be set to negative. if (m_numNewMessages < 0) { #ifdef DEBUG_bienvenu1 @@ -535,6 +536,7 @@ NS_IMETHODIMP nsDBFolderInfo::ChangeNumNewMessages(PRInt32 delta) NS_IMETHODIMP nsDBFolderInfo::ChangeNumMessages(PRInt32 delta) { m_numMessages += delta; + // m_numMessages can never be set to negative. if (m_numMessages < 0) { #ifdef DEBUG_bienvenu @@ -548,6 +550,7 @@ NS_IMETHODIMP nsDBFolderInfo::ChangeNumMessages(PRInt32 delta) NS_IMETHODIMP nsDBFolderInfo::ChangeNumVisibleMessages(PRInt32 delta) { m_numVisibleMessages += delta; + // m_numVisibleMessages can never be set to negative. if (m_numVisibleMessages < 0) { #ifdef DEBUG_bienvenu diff --git a/mailnews/db/msgdb/src/nsMsgDatabase.cpp b/mailnews/db/msgdb/src/nsMsgDatabase.cpp index 682ddca8e53c..e21f28c41cfe 100644 --- a/mailnews/db/msgdb/src/nsMsgDatabase.cpp +++ b/mailnews/db/msgdb/src/nsMsgDatabase.cpp @@ -95,7 +95,7 @@ static NS_DEFINE_CID(kMsgHeaderParserCID, NS_MSGHEADERPARSER_CID); #define MSG_HASH_SIZE 512 -const PRInt32 kMaxHdrsInCache = 512; +const PRInt32 kMaxHdrsInCache = 512; // this will be used on discovery, since we don't know total, and after loading (and sorting), on a new header, we'll use this. // special keys static const nsMsgKey kAllMsgHdrsTableKey = 1; @@ -139,12 +139,12 @@ nsresult nsMsgDatabase::AddHdrToCache(nsIMsgDBHdr *hdr, nsMsgKey key) // do we w if (m_bCacheHeaders) { if (!m_cachedHeaders) - m_cachedHeaders = PL_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), kMaxHdrsInCache ); + m_cachedHeaders = PL_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), m_cacheSize ); if (m_cachedHeaders) { if (key == nsMsgKey_None) hdr->GetMessageKey(&key); - if (m_cachedHeaders->entryCount > kMaxHdrsInCache) + if (m_cachedHeaders->entryCount > m_cacheSize) ClearHdrCache(PR_TRUE); PLDHashEntryHdr *entry = PL_DHashTableOperate(m_cachedHeaders, (void *) key, PL_DHASH_ADD); if (!entry) @@ -170,6 +170,19 @@ nsresult nsMsgDatabase::AddHdrToCache(nsIMsgDBHdr *hdr, nsMsgKey key) // do we w return PL_DHASH_NEXT; } +NS_IMETHODIMP nsMsgDatabase::SetMsgHdrCacheSize(PRUint32 aSize) +{ + m_cacheSize = aSize; + return NS_OK; +} + +NS_IMETHODIMP nsMsgDatabase::GetMsgHdrCacheSize(PRUint32 *aSize) +{ + NS_ENSURE_ARG_POINTER(aSize); + *aSize = m_cacheSize; + return NS_OK; +} + NS_IMETHODIMP nsMsgDatabase::ClearCachedHdrs() { return ClearHdrCache(PR_FALSE); // don't re-init, hope db gets closed. @@ -187,7 +200,7 @@ nsresult nsMsgDatabase::ClearHdrCache(PRBool reInit) if (reInit) { PL_DHashTableFinish(saveCachedHeaders); - PL_DHashTableInit(saveCachedHeaders, &gMsgDBHashTableOps, nsnull, sizeof(struct MsgHdrHashElement), kMaxHdrsInCache); + PL_DHashTableInit(saveCachedHeaders, &gMsgDBHashTableOps, nsnull, sizeof(struct MsgHdrHashElement), m_cacheSize); m_cachedHeaders = saveCachedHeaders; } @@ -672,11 +685,11 @@ nsMsgDatabase::nsMsgDatabase() m_HeaderParser(nsnull), m_headersInUse(nsnull), m_cachedHeaders(nsnull), - m_bCacheHeaders(PR_FALSE) + m_bCacheHeaders(PR_TRUE), + m_cacheSize(kMaxHdrsInCache) { NS_INIT_REFCNT(); - m_bCacheHeaders = PR_TRUE; } nsMsgDatabase::~nsMsgDatabase()