mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-04-02 12:32:55 +00:00
cache virtual folder search results, sr=mscott 276716
This commit is contained in:
parent
8094ac5af0
commit
c5ace2681c
@ -275,6 +275,7 @@ var folderListener = {
|
||||
{
|
||||
gDefaultSearchViewTerms = null;
|
||||
viewDebug("searching gVirtualFolderTerms\n");
|
||||
gDBView.viewFolder = gMsgFolderSelected;
|
||||
loadVirtualFolder();
|
||||
}
|
||||
else if (gMsgFolderSelected.flags & MSG_FOLDER_FLAG_VIRTUAL)
|
||||
|
@ -616,15 +616,6 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch,
|
||||
NS_ENSURE_ARG(aExpressionTree);
|
||||
nsresult err;
|
||||
|
||||
// Don't even bother to look at expunged messages awaiting compression
|
||||
PRUint32 msgFlags;
|
||||
msgToMatch->GetFlags(&msgFlags);
|
||||
if (msgFlags & MSG_FLAG_EXPUNGED)
|
||||
{
|
||||
*pResult = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!*aExpressionTree)
|
||||
{
|
||||
PRUint32 initialPos = 0;
|
||||
|
@ -171,7 +171,8 @@ nsMsgSearchSession::GetNthSearchTerm(PRInt32 whichTerm,
|
||||
NS_IMETHODIMP nsMsgSearchSession::CountSearchScopes(PRInt32 *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG(_retval);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
*_retval = m_scopeList.Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void GetNthSearchScope (in long which, out nsMsgSearchScope scopeId, out nsIMsgFolder folder); */
|
||||
|
@ -2725,6 +2725,13 @@ NS_IMETHODIMP VirtualFolderChangeListener::OnHdrChange(nsIMsgDBHdr *aHdrChanged,
|
||||
if (numNewMessages == 1)
|
||||
m_virtualFolder->SetHasNewMessages(PR_FALSE);
|
||||
}
|
||||
if (totalDelta)
|
||||
{
|
||||
nsXPIDLCString searchUri;
|
||||
m_virtualFolder->GetURI(getter_Copies(searchUri));
|
||||
msgDB->UpdateHdrInCache(searchUri, aHdrChanged, totalDelta == 1);
|
||||
}
|
||||
|
||||
m_virtualFolder->UpdateSummaryTotals(PR_TRUE); // force update from db.
|
||||
virtDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
}
|
||||
@ -2762,6 +2769,10 @@ NS_IMETHODIMP VirtualFolderChangeListener::OnHdrDeleted(nsIMsgDBHdr *aHdrDeleted
|
||||
if (numNewMessages == 1)
|
||||
m_virtualFolder->SetHasNewMessages(PR_FALSE);
|
||||
}
|
||||
nsXPIDLCString searchUri;
|
||||
m_virtualFolder->GetURI(getter_Copies(searchUri));
|
||||
msgDB->UpdateHdrInCache(searchUri, aHdrDeleted, PR_FALSE);
|
||||
|
||||
m_virtualFolder->UpdateSummaryTotals(PR_TRUE); // force update from db.
|
||||
virtDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
}
|
||||
@ -2797,6 +2808,9 @@ NS_IMETHODIMP VirtualFolderChangeListener::OnHdrAdded(nsIMsgDBHdr *aNewHdr, nsMs
|
||||
m_virtualFolder->SetHasNewMessages(PR_TRUE);
|
||||
m_virtualFolder->SetNumNewMessages(numNewMessages + 1);
|
||||
}
|
||||
nsXPIDLCString searchUri;
|
||||
m_virtualFolder->GetURI(getter_Copies(searchUri));
|
||||
msgDB->UpdateHdrInCache(searchUri, aNewHdr, PR_TRUE);
|
||||
dbFolderInfo->ChangeNumMessages(1);
|
||||
m_virtualFolder->UpdateSummaryTotals(true); // force update from db.
|
||||
virtDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
@ -2945,20 +2959,8 @@ NS_IMETHODIMP nsMsgAccountManager::LoadVirtualFolders()
|
||||
// and we have to add a pending listener for each of them.
|
||||
if (buffer.Length())
|
||||
{
|
||||
nsCStringArray folderUris;
|
||||
dbFolderInfo->SetCharPtrProperty("searchFolderUri", buffer.get());
|
||||
folderUris.ParseString(buffer.get(), "|");
|
||||
for (PRInt32 i = 0; i < folderUris.Count(); i++)
|
||||
{
|
||||
rdf->GetResource(*(folderUris[i]), getter_AddRefs(resource));
|
||||
nsCOMPtr <nsIMsgFolder> realFolder = do_QueryInterface(resource);
|
||||
VirtualFolderChangeListener *dbListener = new VirtualFolderChangeListener();
|
||||
m_virtualFolderListeners.AppendObject(dbListener);
|
||||
dbListener->m_virtualFolder = virtualFolder;
|
||||
dbListener->m_folderWatching = realFolder;
|
||||
dbListener->Init();
|
||||
msgDBService->RegisterPendingListener(realFolder, dbListener);
|
||||
}
|
||||
AddVFListenersForVF(virtualFolder, buffer.get(), rdf, msgDBService);
|
||||
}
|
||||
else // this folder is useless
|
||||
{
|
||||
@ -3067,6 +3069,29 @@ nsresult nsMsgAccountManager::WriteLineToOutputStream(const char *prefix, const
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsMsgAccountManager::AddVFListenersForVF(nsIMsgFolder *virtualFolder,
|
||||
const char *srchFolderUris,
|
||||
nsIRDFService *rdf,
|
||||
nsIMsgDBService *msgDBService)
|
||||
{
|
||||
nsCStringArray folderUris;
|
||||
folderUris.ParseString(srchFolderUris, "|");
|
||||
nsCOMPtr <nsIRDFResource> resource;
|
||||
|
||||
for (PRInt32 i = 0; i < folderUris.Count(); i++)
|
||||
{
|
||||
rdf->GetResource(*(folderUris[i]), getter_AddRefs(resource));
|
||||
nsCOMPtr <nsIMsgFolder> realFolder = do_QueryInterface(resource);
|
||||
VirtualFolderChangeListener *dbListener = new VirtualFolderChangeListener();
|
||||
NS_ENSURE_TRUE(dbListener, NS_ERROR_OUT_OF_MEMORY);
|
||||
m_virtualFolderListeners.AppendObject(dbListener);
|
||||
dbListener->m_virtualFolder = virtualFolder;
|
||||
dbListener->m_folderWatching = realFolder;
|
||||
dbListener->Init();
|
||||
msgDBService->RegisterPendingListener(realFolder, dbListener);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgAccountManager::OnItemAdded(nsIRDFResource *parentItem, nsISupports *item)
|
||||
{
|
||||
nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(item);
|
||||
@ -3083,23 +3108,14 @@ NS_IMETHODIMP nsMsgAccountManager::OnItemAdded(nsIRDFResource *parentItem, nsISu
|
||||
nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
|
||||
if (msgDBService)
|
||||
{
|
||||
VirtualFolderChangeListener *dbListener = new VirtualFolderChangeListener();
|
||||
dbListener->m_virtualFolder = folder;
|
||||
nsCOMPtr <nsIMsgDatabase> virtDatabase;
|
||||
nsCOMPtr <nsIDBFolderInfo> dbFolderInfo;
|
||||
m_virtualFolderListeners.AppendObject(dbListener);
|
||||
rv = folder->GetDBFolderInfoAndDB(getter_AddRefs(dbFolderInfo), getter_AddRefs(virtDatabase));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsXPIDLCString srchFolderUri;
|
||||
dbFolderInfo->GetCharPtrProperty("searchFolderUri", getter_Copies(srchFolderUri));
|
||||
// if we supported cross folder virtual folders, we'd have a list of folders uris,
|
||||
// and we'd have to add a pending listener for each of them.
|
||||
rv = GetExistingFolder(srchFolderUri.get(), getter_AddRefs(dbListener->m_folderWatching));
|
||||
if (dbListener->m_folderWatching)
|
||||
{
|
||||
dbListener->Init();
|
||||
msgDBService->RegisterPendingListener(dbListener->m_folderWatching, dbListener);
|
||||
}
|
||||
nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv));
|
||||
AddVFListenersForVF(folder, srchFolderUri, rdf, msgDBService);
|
||||
}
|
||||
rv = SaveVirtualFolders();
|
||||
}
|
||||
|
@ -56,6 +56,8 @@
|
||||
#include "nsIUrlListener.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsIRDFService;
|
||||
|
||||
class nsMsgAccountManager: public nsIMsgAccountManager,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
@ -205,6 +207,10 @@ private:
|
||||
// handle virtual folders
|
||||
nsresult GetVirtualFoldersFile(nsCOMPtr<nsILocalFile>& file);
|
||||
nsresult WriteLineToOutputStream(const char *prefix, const char * line, nsIOutputStream *outputStream);
|
||||
nsresult AddVFListenersForVF(nsIMsgFolder *virtualFolder,
|
||||
const char *srchFolderUris,
|
||||
nsIRDFService *rdf,
|
||||
nsIMsgDBService *msgDBService);
|
||||
|
||||
static void getUniqueKey(const char* prefix,
|
||||
nsHashtable *hashTable,
|
||||
|
@ -4178,7 +4178,10 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsMsgKeyAr
|
||||
nsMsgViewIndex tryIndex = (lowIndex + highIndex - 1) / 2;
|
||||
EntryInfo2.id = keys->GetAt(tryIndex);
|
||||
nsCOMPtr <nsIMsgDBHdr> tryHdr;
|
||||
rv = m_db->GetMsgHdrForKey(EntryInfo2.id, getter_AddRefs(tryHdr));
|
||||
nsCOMPtr <nsIMsgDatabase> db;
|
||||
GetDBForViewIndex(tryIndex, getter_AddRefs(db));
|
||||
if (db)
|
||||
rv = db->GetMsgHdrForKey(EntryInfo2.id, getter_AddRefs(tryHdr));
|
||||
if (!tryHdr)
|
||||
break;
|
||||
if (fieldType == kCollationKey)
|
||||
|
@ -48,6 +48,8 @@
|
||||
|
||||
nsMsgQuickSearchDBView::nsMsgQuickSearchDBView()
|
||||
{
|
||||
m_usingCachedHits = PR_FALSE;
|
||||
m_cacheEmpty = PR_TRUE;
|
||||
}
|
||||
|
||||
nsMsgQuickSearchDBView::~nsMsgQuickSearchDBView()
|
||||
@ -219,17 +221,55 @@ nsMsgQuickSearchDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder)
|
||||
NS_ENSURE_ARG(aMsgHdr);
|
||||
if (!m_db)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
// remember search hit and when search is done, reconcile cache
|
||||
// with new hits;
|
||||
m_hdrHits.AppendObject(aMsgHdr);
|
||||
nsMsgKey key;
|
||||
aMsgHdr->GetMessageKey(&key);
|
||||
// is FindKey going to be expensive here? A lot of hits could make
|
||||
// it a little bit slow to search through the view for every hit.
|
||||
if (m_cacheEmpty || FindKey(key, PR_FALSE) == nsMsgViewIndex_None)
|
||||
return AddHdr(aMsgHdr);
|
||||
else
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgQuickSearchDBView::OnSearchDone(nsresult status)
|
||||
{
|
||||
if (m_viewFolder)
|
||||
{
|
||||
nsMsgKeyArray keyArray;
|
||||
nsXPIDLCString searchUri;
|
||||
m_viewFolder->GetURI(getter_Copies(searchUri));
|
||||
PRUint32 count = m_hdrHits.Count();
|
||||
// build up message keys.
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
nsMsgKey key;
|
||||
m_hdrHits[i]->GetMessageKey(&key);
|
||||
keyArray.Add(key);
|
||||
}
|
||||
nsMsgKey *staleHits;
|
||||
PRUint32 numBadHits;
|
||||
m_db->RefreshCache(searchUri, m_hdrHits.Count(), keyArray.GetArray(), &numBadHits, &staleHits);
|
||||
for (i = 0; i < numBadHits; i++)
|
||||
{
|
||||
nsMsgViewIndex staleHitIndex = FindKey(staleHits[i], PR_TRUE);
|
||||
if (staleHitIndex != nsMsgViewIndex_None)
|
||||
RemoveByIndex(staleHitIndex);
|
||||
}
|
||||
delete [] staleHits;
|
||||
// we also need to add new hits - should we have RefreshCache calculate these?
|
||||
// or just look through the view for each hit to see if we're already displaying it?
|
||||
}
|
||||
if (m_sortType != nsMsgViewSortType::byThread)//we do not find levels for the results.
|
||||
{
|
||||
m_sortValid = PR_FALSE; //sort the results
|
||||
Sort(m_sortType, m_sortOrder);
|
||||
}
|
||||
m_hdrHits.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -242,11 +282,41 @@ nsMsgQuickSearchDBView::OnNewSearch()
|
||||
m_keys.RemoveAll();
|
||||
m_levels.RemoveAll();
|
||||
m_flags.RemoveAll();
|
||||
|
||||
m_hdrHits.Clear();
|
||||
// this needs to happen after we remove all the keys, since RowCountChanged() will call our GetRowCount()
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(0, -oldSize);
|
||||
PRUint32 folderFlags = 0;
|
||||
if (m_viewFolder)
|
||||
m_viewFolder->GetFlags(&folderFlags);
|
||||
// check if it's a virtual folder - if so, we should get the cached hits
|
||||
// from the db, and set a flag saying that we're using cached values.
|
||||
if (folderFlags & MSG_FOLDER_FLAG_VIRTUAL)
|
||||
{
|
||||
nsCOMPtr<nsISimpleEnumerator> cachedHits;
|
||||
nsXPIDLCString searchUri;
|
||||
m_viewFolder->GetURI(getter_Copies(searchUri));
|
||||
m_db->GetCachedHits(searchUri, getter_AddRefs(cachedHits));
|
||||
if (cachedHits)
|
||||
{
|
||||
PRBool hasMore;
|
||||
|
||||
m_usingCachedHits = PR_TRUE;
|
||||
cachedHits->HasMoreElements(&hasMore);
|
||||
m_cacheEmpty = !hasMore;
|
||||
while (hasMore)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> pHeader;
|
||||
nsresult rv = cachedHits->GetNext(getter_AddRefs(pHeader));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
|
||||
if (pHeader && NS_SUCCEEDED(rv))
|
||||
AddHdr(pHeader);
|
||||
else
|
||||
break;
|
||||
cachedHits->HasMoreElements(&hasMore);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,9 @@
|
||||
#include "nsMsgThreadedDBView.h"
|
||||
#include "nsIMsgSearchNotify.h"
|
||||
#include "nsIMsgSearchSession.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIMsgHdr.h"
|
||||
|
||||
|
||||
class nsMsgQuickSearchDBView : public nsMsgThreadedDBView, public nsIMsgSearchNotify
|
||||
{
|
||||
@ -66,6 +69,9 @@ public:
|
||||
protected:
|
||||
nsWeakPtr m_searchSession;
|
||||
nsMsgKeyArray m_origKeys;
|
||||
PRBool m_usingCachedHits;
|
||||
PRBool m_cacheEmpty;
|
||||
nsCOMArray <nsIMsgDBHdr> m_hdrHits;
|
||||
virtual nsresult OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey aParentKey, PRBool ensureListed);
|
||||
virtual nsresult SortThreads(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder);
|
||||
virtual nsresult GetFirstMessageHdrToDisplayInThread(nsIMsgThread *threadHdr, nsIMsgDBHdr **result);
|
||||
|
@ -190,6 +190,27 @@ nsresult nsMsgSearchDBView::GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDataba
|
||||
return NS_MSG_INVALID_DBVIEW_INDEX;
|
||||
}
|
||||
|
||||
nsresult nsMsgSearchDBView::AddHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder)
|
||||
{
|
||||
m_folders->AppendElement(folder);
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags;
|
||||
msgHdr->GetMessageKey(&msgKey);
|
||||
// nsMsgKey_None means it's not a valid hdr.
|
||||
if (msgKey != nsMsgKey_None)
|
||||
{
|
||||
msgHdr->GetFlags(&msgFlags);
|
||||
m_keys.Add(msgKey);
|
||||
m_levels.Add(0);
|
||||
m_flags.Add(msgFlags);
|
||||
|
||||
// this needs to be called after we add the key, since RowCountChanged() will call our GetRowCount()
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(GetSize() - 1, 1);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgSearchDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder)
|
||||
{
|
||||
@ -209,20 +230,7 @@ nsMsgSearchDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder)
|
||||
}
|
||||
}
|
||||
|
||||
m_folders->AppendElement(supports);
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags;
|
||||
aMsgHdr->GetMessageKey(&msgKey);
|
||||
aMsgHdr->GetFlags(&msgFlags);
|
||||
m_keys.Add(msgKey);
|
||||
m_levels.Add(0);
|
||||
m_flags.Add(msgFlags);
|
||||
|
||||
// this needs to be called after we add the key, since RowCountChanged() will call our GetRowCount()
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(GetSize() - 1, 1);
|
||||
|
||||
return NS_OK;
|
||||
return AddHdrFromFolder(aMsgHdr, supports);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -518,7 +526,7 @@ nsresult nsMsgSearchDBView::ProcessRequestsInOneFolder(nsIMsgWindow *window)
|
||||
|
||||
// called for delete with trash, copy and move
|
||||
if (mCommand == nsMsgViewCommandType::deleteMsg)
|
||||
curFolder->DeleteMessages(messageArray, window, PR_FALSE /* delete storage */, PR_FALSE /* is move*/, this, PR_FALSE /*allowUndo*/);
|
||||
curFolder->DeleteMessages(messageArray, window, PR_FALSE /* delete storage */, PR_FALSE /* is move*/, this, PR_TRUE /*allowUndo*/);
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(!(curFolder == mDestFolder), "The source folder and the destination folder are the same");
|
||||
@ -528,9 +536,9 @@ nsresult nsMsgSearchDBView::ProcessRequestsInOneFolder(nsIMsgWindow *window)
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
if (mCommand == nsMsgViewCommandType::moveMessages)
|
||||
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_TRUE /* isMove */, this, window, PR_FALSE /*allowUndo*/);
|
||||
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_TRUE /* isMove */, this, window, PR_TRUE /*allowUndo*/);
|
||||
else if (mCommand == nsMsgViewCommandType::copyMessages)
|
||||
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_FALSE /* isMove */, this, window, PR_FALSE /*allowUndo*/);
|
||||
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_FALSE /* isMove */, this, window, PR_TRUE /*allowUndo*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
|
||||
protected:
|
||||
nsresult FetchLocation(PRInt32 aRow, PRUnichar ** aLocationString);
|
||||
virtual nsresult AddHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder);
|
||||
virtual nsresult GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDatabase **db);
|
||||
virtual nsresult RemoveByIndex(nsMsgViewIndex index);
|
||||
virtual nsresult CopyMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, PRInt32 numIndices, PRBool isMove, nsIMsgFolder *destFolder);
|
||||
|
@ -142,6 +142,86 @@ nsresult nsMsgXFVirtualFolderDBView::OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey a
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsMsgXFVirtualFolderDBView::InsertHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder)
|
||||
{
|
||||
nsMsgViewIndex insertIndex = GetInsertIndex(msgHdr);
|
||||
if (insertIndex == nsMsgViewIndex_None)
|
||||
return AddHdrFromFolder(msgHdr, folder);
|
||||
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags;
|
||||
msgHdr->GetMessageKey(&msgKey);
|
||||
msgHdr->GetFlags(&msgFlags);
|
||||
m_keys.InsertAt(insertIndex, msgKey);
|
||||
m_flags.InsertAt(insertIndex, msgFlags);
|
||||
m_folders->InsertElementAt(folder, insertIndex);
|
||||
m_levels.InsertAt((PRInt32) insertIndex, (PRUint8) 0);
|
||||
|
||||
// the call to NoteChange() has to happen after we add the key
|
||||
// as NoteChange() will call RowCountChanged() which will call our GetRowCount()
|
||||
NoteChange(insertIndex, 1, nsMsgViewNotificationCode::insertOrDelete);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsMsgXFVirtualFolderDBView::UpdateCacheAndViewForFolder(nsIMsgFolder *folder, nsMsgKey *newHits, PRUint32 numNewHits)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDatabase> db;
|
||||
nsresult rv = folder->GetMsgDatabase(nsnull, getter_AddRefs(db));
|
||||
if (NS_SUCCEEDED(rv) && db)
|
||||
{
|
||||
nsXPIDLCString searchUri;
|
||||
m_viewFolder->GetURI(getter_Copies(searchUri));
|
||||
PRUint32 numBadHits;
|
||||
nsMsgKey *badHits;
|
||||
rv = db->RefreshCache(searchUri, numNewHits, newHits,
|
||||
&numBadHits, &badHits);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
for (PRUint32 badHitIndex = 0; badHitIndex < numBadHits; badHitIndex++)
|
||||
{
|
||||
// of course, this isn't quite right
|
||||
nsMsgViewIndex staleHitIndex = FindKey(badHits[badHitIndex], PR_TRUE);
|
||||
if (staleHitIndex != nsMsgViewIndex_None)
|
||||
RemoveByIndex(staleHitIndex);
|
||||
}
|
||||
delete [] badHits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsMsgXFVirtualFolderDBView::UpdateCacheAndViewForPrevSearchedFolders(nsIMsgFolder *curSearchFolder)
|
||||
{
|
||||
// Handle the most recent folder with hits, if any.
|
||||
if (m_curFolderGettingHits)
|
||||
{
|
||||
PRUint32 count = m_hdrHits.Count();
|
||||
nsMsgKeyArray newHits;
|
||||
for (PRUint32 i = 0; i < count; i++)
|
||||
{
|
||||
nsMsgKey key;
|
||||
m_hdrHits[i]->GetMessageKey(&key);
|
||||
newHits.Add(key);
|
||||
}
|
||||
UpdateCacheAndViewForFolder(m_curFolderGettingHits, newHits.GetArray(), newHits.GetSize());
|
||||
}
|
||||
|
||||
while (m_foldersWithNonVerifiedCachedHits.Count() > 0)
|
||||
{
|
||||
// this new folder has cached hits.
|
||||
if (m_foldersWithNonVerifiedCachedHits[0] == curSearchFolder)
|
||||
{
|
||||
m_curFolderHasCachedHits = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
else if (m_foldersWithNonVerifiedCachedHits[0] != m_curFolderGettingHits)
|
||||
{
|
||||
// this must be a folder that had cached hits but no hits with
|
||||
// the current search. So all cached hits need to be removed.
|
||||
UpdateCacheAndViewForFolder(m_foldersWithNonVerifiedCachedHits[0], 0, nsnull);
|
||||
}
|
||||
m_foldersWithNonVerifiedCachedHits.RemoveObjectAt(0);
|
||||
}
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsMsgXFVirtualFolderDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder)
|
||||
{
|
||||
@ -149,32 +229,54 @@ nsMsgXFVirtualFolderDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *fold
|
||||
NS_ENSURE_ARG(folder);
|
||||
|
||||
nsCOMPtr <nsISupports> supports = do_QueryInterface(folder);
|
||||
nsCOMPtr<nsIMsgDatabase> dbToUse;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
folder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse));
|
||||
|
||||
if (m_folders->IndexOf(supports) < 0 ) //do this just for new folder
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> dbToUse;
|
||||
nsCOMPtr<nsIDBFolderInfo> folderInfo;
|
||||
folder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse));
|
||||
if (dbToUse)
|
||||
{
|
||||
dbToUse->AddListener(this);
|
||||
m_dbToUseList.AppendObject(dbToUse);
|
||||
}
|
||||
}
|
||||
if (m_curFolderGettingHits != folder)
|
||||
{
|
||||
m_curFolderHasCachedHits = PR_FALSE;
|
||||
// since we've gotten a hit for a new folder, the searches for
|
||||
// any previous folders are done, so deal with stale cached hits
|
||||
// for those folders now.
|
||||
|
||||
m_folders->AppendElement(supports);
|
||||
nsMsgKey msgKey;
|
||||
PRUint32 msgFlags;
|
||||
aMsgHdr->GetMessageKey(&msgKey);
|
||||
aMsgHdr->GetFlags(&msgFlags);
|
||||
m_keys.Add(msgKey);
|
||||
m_levels.Add(0);
|
||||
m_flags.Add(msgFlags);
|
||||
|
||||
// this needs to be called after we add the key, since RowCountChanged() will call our GetRowCount()
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(GetSize() - 1, 1);
|
||||
UpdateCacheAndViewForPrevSearchedFolders(folder);
|
||||
m_curFolderGettingHits = folder;
|
||||
m_hdrHits.Clear();
|
||||
m_curFolderStartKeyIndex = m_keys.GetSize();
|
||||
}
|
||||
// calling FindHdr is sub-optimal here since for virtual folders with
|
||||
// a large number of hits, we'll have an 0(n2) algorithm
|
||||
// - we could add a way to check if a hdr is in the cached hits for
|
||||
// this folder, or we could make FindHdr do a binary search when
|
||||
// the view is sorted. Checking the cached hits is probably best
|
||||
// since they're in id order, so we can do a binary search.
|
||||
// Actually, I think Mork has a hash table for uid lookups in a
|
||||
// table, so we should definitely use the db.
|
||||
PRBool hdrInCache = PR_FALSE;
|
||||
nsXPIDLCString searchUri;
|
||||
m_viewFolder->GetURI(getter_Copies(searchUri));
|
||||
dbToUse->HdrIsInCache(searchUri, aMsgHdr, &hdrInCache);
|
||||
if (!m_curFolderHasCachedHits || !hdrInCache)
|
||||
{
|
||||
if (m_sortValid)
|
||||
InsertHdrFromFolder(aMsgHdr, supports);
|
||||
else
|
||||
AddHdrFromFolder(aMsgHdr, supports);
|
||||
}
|
||||
m_hdrHits.AppendObject(aMsgHdr);
|
||||
|
||||
m_numTotal++;
|
||||
PRUint32 msgFlags;
|
||||
aMsgHdr->GetFlags(&msgFlags);
|
||||
if (!(msgFlags & MSG_FLAG_READ))
|
||||
m_numUnread++;
|
||||
|
||||
@ -184,6 +286,9 @@ nsMsgXFVirtualFolderDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *fold
|
||||
NS_IMETHODIMP
|
||||
nsMsgXFVirtualFolderDBView::OnSearchDone(nsresult status)
|
||||
{
|
||||
// handle any non verified hits we haven't handled yet.
|
||||
UpdateCacheAndViewForPrevSearchedFolders(nsnull);
|
||||
|
||||
//we want to set imap delete model once the search is over because setting next
|
||||
//message after deletion will happen before deleting the message and search scope
|
||||
//can change with every search.
|
||||
@ -200,11 +305,13 @@ nsMsgXFVirtualFolderDBView::OnSearchDone(nsresult status)
|
||||
dbFolderInfo->SetNumMessages(m_numTotal);
|
||||
m_viewFolder->UpdateSummaryTotals(true); // force update from db.
|
||||
virtDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
if (m_sortType != nsMsgViewSortType::byThread)
|
||||
if (!m_sortValid && m_sortType != nsMsgViewSortType::byThread)
|
||||
{
|
||||
m_sortValid = PR_FALSE; //sort the results
|
||||
Sort(m_sortType, m_sortOrder);
|
||||
}
|
||||
m_foldersWithNonVerifiedCachedHits.Clear();
|
||||
m_curFolderGettingHits = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -229,6 +336,73 @@ nsMsgXFVirtualFolderDBView::OnNewSearch()
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(0, -oldSize);
|
||||
|
||||
// to use the search results cache, we'll need to iterate over the scopes in the
|
||||
// search session, calling getNthSearchScope for i = 0; i < searchSession.countSearchScopes; i++
|
||||
// and for each folder, then open the db and pull out the cached hits, add them to the view.
|
||||
// For each hit in a new folder, we'll then clean up the stale hits from the previous folder(s).
|
||||
|
||||
PRInt32 scopeCount;
|
||||
nsCOMPtr <nsIMsgSearchSession> searchSession = do_QueryReferent(m_searchSession);
|
||||
searchSession->CountSearchScopes(&scopeCount);
|
||||
for (PRInt32 i = 0; i < scopeCount; i++)
|
||||
{
|
||||
nsMsgSearchScopeValue scopeId;
|
||||
nsCOMPtr<nsIMsgFolder> searchFolder;
|
||||
searchSession->GetNthSearchScope(i, &scopeId, getter_AddRefs(searchFolder));
|
||||
if (searchFolder)
|
||||
{
|
||||
nsCOMPtr<nsISimpleEnumerator> cachedHits;
|
||||
nsCOMPtr<nsIMsgDatabase> searchDB;
|
||||
nsXPIDLCString searchUri;
|
||||
m_viewFolder->GetURI(getter_Copies(searchUri));
|
||||
nsresult rv = searchFolder->GetMsgDatabase(nsnull, getter_AddRefs(searchDB));
|
||||
if (NS_SUCCEEDED(rv) && searchDB)
|
||||
{
|
||||
searchDB->GetCachedHits(searchUri, getter_AddRefs(cachedHits));
|
||||
PRBool hasMore;
|
||||
if (cachedHits)
|
||||
{
|
||||
cachedHits->HasMoreElements(&hasMore);
|
||||
if (hasMore)
|
||||
{
|
||||
nsMsgKey prevKey = nsMsgKey_None;
|
||||
m_foldersWithNonVerifiedCachedHits.AppendObject(searchFolder);
|
||||
while (hasMore)
|
||||
{
|
||||
nsCOMPtr <nsIMsgDBHdr> pHeader;
|
||||
nsresult rv = cachedHits->GetNext(getter_AddRefs(pHeader));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
|
||||
if (pHeader && NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsMsgKey msgKey;
|
||||
pHeader->GetMessageKey(&msgKey);
|
||||
NS_ASSERTION(prevKey == nsMsgKey_None || msgKey > prevKey, "cached Hits not sorted");
|
||||
prevKey = msgKey;
|
||||
AddHdrFromFolder(pHeader, searchFolder); // need to QI to nsISupports?
|
||||
}
|
||||
else
|
||||
break;
|
||||
cachedHits->HasMoreElements(&hasMore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_curFolderStartKeyIndex = 0;
|
||||
m_curFolderGettingHits = nsnull;
|
||||
m_curFolderHasCachedHits = PR_FALSE;
|
||||
|
||||
// if we have cached hits, sort them.
|
||||
if (GetSize() > 0)
|
||||
{
|
||||
if (m_sortType != nsMsgViewSortType::byThread)
|
||||
{
|
||||
m_sortValid = PR_FALSE; //sort the results
|
||||
Sort(m_sortType, m_sortOrder);
|
||||
}
|
||||
}
|
||||
// mSearchResults->Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -65,11 +65,20 @@ public:
|
||||
NS_IMETHOD GetViewType(nsMsgViewTypeValue *aViewType);
|
||||
NS_IMETHOD DoCommand(nsMsgViewCommandTypeValue command);
|
||||
virtual nsresult OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey parentKey, PRBool ensureListed);
|
||||
virtual nsresult InsertHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder);
|
||||
NS_IMETHOD GetMsgFolder(nsIMsgFolder **aMsgFolder);
|
||||
void UpdateCacheAndViewForPrevSearchedFolders(nsIMsgFolder *curSearchFolder);
|
||||
void UpdateCacheAndViewForFolder(nsIMsgFolder *folder, nsMsgKey *newHits, PRUint32 numNewHits);
|
||||
|
||||
protected:
|
||||
|
||||
nsCOMPtr <nsIMsgFolder> m_viewFolder;
|
||||
PRUint32 m_cachedFolderArrayIndex; // array index of next folder with cached hits to deal with.
|
||||
nsCOMArray<nsIMsgFolder> m_foldersWithNonVerifiedCachedHits;
|
||||
nsCOMArray<nsIMsgDBHdr> m_hdrHits;
|
||||
nsCOMPtr <nsIMsgFolder> m_curFolderGettingHits;
|
||||
PRUint32 m_curFolderStartKeyIndex; // keeps track of the index of the first hit from the cur folder
|
||||
PRBool m_curFolderHasCachedHits;
|
||||
nsWeakPtr m_searchSession;
|
||||
PRInt32 m_numUnread;
|
||||
PRInt32 m_numTotal;
|
||||
|
@ -54,6 +54,7 @@ interface nsIMsgOfflineImapOperation;
|
||||
interface nsIMsgFolder;
|
||||
interface nsIOFileStream;
|
||||
interface nsIUrlListener;
|
||||
interface nsISupportsArray;
|
||||
|
||||
[ptr] native octetPtr(PRUint8);
|
||||
|
||||
@ -117,7 +118,7 @@ interface nsIMsgDBService : nsISupports
|
||||
void unregisterPendingListener(in nsIDBChangeListener aListener);
|
||||
};
|
||||
|
||||
[scriptable, uuid(7b510984-bbac-4e8f-b6cd-134509000776)]
|
||||
[scriptable, uuid(6393FEF1-D6C6-444A-90B8-BEC84E8BD8D7)]
|
||||
|
||||
interface nsIMsgDatabase : nsIDBChangeAnnouncer {
|
||||
void Open(in nsIFileSpec aFolderName, in boolean aCreate, in boolean aLeaveInvalidDB);
|
||||
@ -301,5 +302,13 @@ interface nsIMsgDatabase : nsIDBChangeAnnouncer {
|
||||
* the caller should free when done using nsMemory::Free.
|
||||
*/
|
||||
void getNewList(out unsigned long count, [array, size_is(count)] out nsMsgKey newKeys);
|
||||
|
||||
// These are used for caching search hits in a db, to speed up saved search folders.
|
||||
nsISimpleEnumerator getCachedHits(in string aSearchFolderUri);
|
||||
void refreshCache(in string aSearchFolderUri, in unsigned long aNumKeys, [array, size_is (aNumKeys)] in nsMsgKey aNewHits,
|
||||
out unsigned long aNumBadHits, [array, size_is(aNumBadHits)] out nsMsgKey aStaleHits);
|
||||
void updateHdrInCache(in string aSearchFolderUri, in nsIMsgDBHdr aHdr, in boolean aAdd);
|
||||
boolean hdrIsInCache(in string aSearchFolderUri, in nsIMsgDBHdr aHdr);
|
||||
|
||||
};
|
||||
|
||||
|
@ -95,6 +95,7 @@ public:
|
||||
virtual nsresult CreateMsgHdr(nsIMdbRow* hdrRow, nsMsgKey key, nsIMsgDBHdr **result);
|
||||
virtual nsresult GetThreadForMsgKey(nsMsgKey msgKey, nsIMsgThread **result);
|
||||
virtual nsresult EnumerateMessagesWithFlag(nsISimpleEnumerator* *result, PRUint32 *pFlag);
|
||||
nsresult GetSearchResultsTable(const char *searchFolderUri, PRBool createIfMissing, nsIMdbTable **table);
|
||||
|
||||
// this might just be for debugging - we'll see.
|
||||
nsresult ListAllThreads(nsMsgKeyArray *threadIds);
|
||||
@ -289,6 +290,8 @@ protected:
|
||||
nsresult ClearUseHdrCache();
|
||||
nsresult RemoveHdrFromUseCache(nsIMsgDBHdr *hdr, nsMsgKey key);
|
||||
|
||||
mdb_pos FindInsertIndexInSortedTable(nsIMdbTable *table, mdb_id idToInsert);
|
||||
|
||||
void ClearCachedObjects(PRBool dbGoingAway);
|
||||
// all instantiated headers, but doesn't hold refs.
|
||||
PLDHashTable *m_headersInUse;
|
||||
|
@ -156,7 +156,7 @@ NS_IMETHODIMP nsMsgDBService::OpenFolderDB(nsIMsgFolder *aFolder, PRBool aCreate
|
||||
PRInt32 numMessages;
|
||||
msgDatabase->m_mdbAllMsgHeadersTable->GetCount(msgDatabase->GetEnv(), &numHdrsInTable);
|
||||
msgDatabase->m_dbFolderInfo->GetNumMessages(&numMessages);
|
||||
if (numMessages != numHdrsInTable)
|
||||
if (numMessages != (PRInt32) numHdrsInTable)
|
||||
msgDatabase->SyncCounts();
|
||||
}
|
||||
}
|
||||
@ -2130,7 +2130,7 @@ nsMsgDatabase::MarkThreadIgnored(nsIMsgThread *thread, nsMsgKey threadKey, PRBoo
|
||||
|
||||
nsCOMPtr <nsIMsgDBHdr> msg;
|
||||
nsresult rv = GetMsgHdrForKey(threadKey, getter_AddRefs(msg));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NotifyHdrChangeAll(msg, oldThreadFlags, threadFlags, instigator);
|
||||
}
|
||||
|
||||
@ -2545,7 +2545,7 @@ public:
|
||||
// nsMsgDBEnumerator methods:
|
||||
typedef nsresult (*nsMsgDBEnumeratorFilter)(nsIMsgDBHdr* hdr, void* closure);
|
||||
|
||||
nsMsgDBEnumerator(nsMsgDatabase* db,
|
||||
nsMsgDBEnumerator(nsMsgDatabase* db, nsIMdbTable *table,
|
||||
nsMsgDBEnumeratorFilter filter, void* closure);
|
||||
virtual ~nsMsgDBEnumerator();
|
||||
|
||||
@ -2558,16 +2558,20 @@ protected:
|
||||
PRBool mDone;
|
||||
PRBool mNextPrefetched;
|
||||
nsMsgDBEnumeratorFilter mFilter;
|
||||
nsCOMPtr <nsIMdbTable> mTable;
|
||||
void* mClosure;
|
||||
};
|
||||
|
||||
nsMsgDBEnumerator::nsMsgDBEnumerator(nsMsgDatabase* db,
|
||||
nsMsgDBEnumeratorFilter filter, void* closure)
|
||||
nsIMdbTable *table,
|
||||
nsMsgDBEnumeratorFilter filter,
|
||||
void* closure)
|
||||
: mDB(db), mRowCursor(nsnull), mResultHdr(nsnull), mDone(PR_FALSE),
|
||||
mFilter(filter), mClosure(closure)
|
||||
{
|
||||
NS_ADDREF(mDB);
|
||||
mNextPrefetched = PR_FALSE;
|
||||
mTable = table;
|
||||
}
|
||||
|
||||
nsMsgDBEnumerator::~nsMsgDBEnumerator()
|
||||
@ -2584,10 +2588,10 @@ nsresult nsMsgDBEnumerator::GetRowCursor()
|
||||
{
|
||||
mDone = PR_FALSE;
|
||||
|
||||
if (!mDB || !mDB->m_mdbAllMsgHeadersTable)
|
||||
if (!mDB || !mTable)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
return mDB->m_mdbAllMsgHeadersTable->GetTableRowCursor(mDB->GetEnv(), -1, &mRowCursor);
|
||||
return mTable->GetTableRowCursor(mDB->GetEnv(), -1, &mRowCursor);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgDBEnumerator::GetNext(nsISupports **aItem)
|
||||
@ -2683,7 +2687,7 @@ NS_IMETHODIMP nsMsgDBEnumerator::HasMoreElements(PRBool *aResult)
|
||||
NS_IMETHODIMP
|
||||
nsMsgDatabase::EnumerateMessages(nsISimpleEnumerator* *result)
|
||||
{
|
||||
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, nsnull, nsnull);
|
||||
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, m_mdbAllMsgHeadersTable, nsnull, nsnull);
|
||||
if (e == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
@ -2978,7 +2982,7 @@ nsMsgFlagSetFilter(nsIMsgDBHdr *msg, void *closure)
|
||||
nsresult
|
||||
nsMsgDatabase::EnumerateMessagesWithFlag(nsISimpleEnumerator* *result, PRUint32 *pFlag)
|
||||
{
|
||||
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, nsMsgFlagSetFilter, pFlag);
|
||||
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, m_mdbAllMsgHeadersTable, nsMsgFlagSetFilter, pFlag);
|
||||
if (e == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
@ -4790,3 +4794,233 @@ nsMsgDatabase::GetNewList(PRUint32 *aCount, PRUint32 **aNewKeys)
|
||||
*aNewKeys = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsMsgDatabase::GetSearchResultsTable(const char *searchFolderUri, PRBool createIfMissing, nsIMdbTable **table)
|
||||
{
|
||||
mdb_kind kindToken;
|
||||
mdb_count numTables;
|
||||
mdb_bool mustBeUnique;
|
||||
mdb_err err = m_mdbStore->StringToToken(GetEnv(), searchFolderUri, &kindToken);
|
||||
err = m_mdbStore->GetTableKind(GetEnv(), m_hdrRowScopeToken, kindToken,
|
||||
&numTables, &mustBeUnique, table);
|
||||
if ((!*table || NS_FAILED(err)) && createIfMissing)
|
||||
err = m_mdbStore->NewTable(GetEnv(), m_hdrRowScopeToken, kindToken, PR_TRUE, nsnull, table);
|
||||
|
||||
return *table ? err : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMsgDatabase::GetCachedHits(const char *aSearchFolderUri, nsISimpleEnumerator **aEnumerator)
|
||||
{
|
||||
nsCOMPtr <nsIMdbTable> table;
|
||||
nsresult err = GetSearchResultsTable(aSearchFolderUri, PR_FALSE, getter_AddRefs(table));
|
||||
NS_ENSURE_SUCCESS(err, err);
|
||||
if (!table)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsMsgDBEnumerator* e = new nsMsgDBEnumerator(this, table, nsnull, nsnull);
|
||||
if (e == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aEnumerator = e);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgDatabase::RefreshCache(const char *aSearchFolderUri, PRUint32 aNumKeys, nsMsgKey *aNewHits, PRUint32 *aNumBadHits, nsMsgKey **aStaleHits)
|
||||
{
|
||||
nsCOMPtr <nsIMdbTable> table;
|
||||
nsresult err = GetSearchResultsTable(aSearchFolderUri, PR_TRUE, getter_AddRefs(table));
|
||||
NS_ENSURE_SUCCESS(err, err);
|
||||
// update the table so that it just contains aNewHits.
|
||||
// And, keep track of the headers in the original table but not in aNewHits, so we
|
||||
// can put those in aStaleHits.
|
||||
// both aNewHits and the db table are sorted by uid/key.
|
||||
// So, start at the beginning of the table and the aNewHits array.
|
||||
PRUint32 newHitIndex = 0;
|
||||
PRUint32 tableRowIndex = 0;
|
||||
|
||||
PRUint32 rowCount;
|
||||
table->GetCount(GetEnv(), &rowCount);
|
||||
nsMsgKeyArray staleHits;
|
||||
// should assert that each array is sorted
|
||||
while (newHitIndex < aNumKeys || tableRowIndex < rowCount)
|
||||
{
|
||||
mdbOid oid;
|
||||
nsMsgKey tableRowKey = nsMsgKey_None;
|
||||
if (tableRowIndex < rowCount)
|
||||
{
|
||||
nsresult ret = table->PosToOid (GetEnv(), tableRowIndex, &oid);
|
||||
if (NS_FAILED(ret))
|
||||
{
|
||||
tableRowIndex++;
|
||||
continue;
|
||||
}
|
||||
tableRowKey = oid.mOid_Id; // ### TODO need the real key for the 0th key problem.
|
||||
}
|
||||
|
||||
if (newHitIndex < aNumKeys && aNewHits[newHitIndex] == tableRowKey)
|
||||
{
|
||||
newHitIndex++;
|
||||
tableRowIndex++;
|
||||
continue;
|
||||
}
|
||||
else if (tableRowIndex >= rowCount || (newHitIndex < aNumKeys && aNewHits[newHitIndex] < tableRowKey))
|
||||
{
|
||||
nsCOMPtr <nsIMdbRow> hdrRow;
|
||||
mdbOid rowObjectId;
|
||||
|
||||
rowObjectId.mOid_Id = aNewHits[newHitIndex];
|
||||
rowObjectId.mOid_Scope = m_hdrRowScopeToken;
|
||||
err = m_mdbStore->GetRow(GetEnv(), &rowObjectId, getter_AddRefs(hdrRow));
|
||||
if (hdrRow)
|
||||
{
|
||||
table->AddRow(GetEnv(), hdrRow);
|
||||
mdb_pos newPos;
|
||||
#ifdef DEBUG_David_Bienvenu
|
||||
printf("adding row %lx at pos %lx \n", rowObjectId.mOid_Id, tableRowIndex);
|
||||
#endif
|
||||
table->MoveRow(GetEnv(), hdrRow, rowCount, tableRowIndex, &newPos);
|
||||
rowCount++;
|
||||
tableRowIndex++;
|
||||
}
|
||||
newHitIndex++;
|
||||
continue;
|
||||
}
|
||||
else if (newHitIndex >= aNumKeys || aNewHits[newHitIndex] > tableRowKey)
|
||||
{
|
||||
staleHits.Add(tableRowKey);
|
||||
table->CutOid(GetEnv(), &oid);
|
||||
rowCount--;
|
||||
continue; // don't increment tableRowIndex since we removed that row.
|
||||
}
|
||||
}
|
||||
*aNumBadHits = staleHits.GetSize();
|
||||
if (*aNumBadHits)
|
||||
{
|
||||
*aStaleHits = NS_STATIC_CAST(PRUint32 *, nsMemory::Alloc(*aNumBadHits * sizeof(PRUint32)));
|
||||
if (!*aStaleHits)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(*aStaleHits, staleHits.GetArray(), *aNumBadHits * sizeof(PRUint32));
|
||||
}
|
||||
else
|
||||
*aStaleHits = nsnull;
|
||||
|
||||
#ifdef DEBUG_David_Bienvenu
|
||||
printf("after refreshing cache\n");
|
||||
// iterate over table and assert that it's in id order
|
||||
table->GetCount(GetEnv(), &rowCount);
|
||||
mdbOid oid;
|
||||
tableRowIndex = 0;
|
||||
mdb_id prevId = 0;
|
||||
while (tableRowIndex < rowCount)
|
||||
{
|
||||
nsresult ret = table->PosToOid (m_mdbEnv, tableRowIndex++, &oid);
|
||||
if (tableRowIndex > 1 && oid.mOid_Id <= prevId)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "inserting row into cached hits table, not sorted correctly");
|
||||
printf("key %lx is before or equal %lx \n", prevId, oid.mOid_Id);
|
||||
}
|
||||
prevId = oid.mOid_Id;
|
||||
}
|
||||
|
||||
#endif
|
||||
Commit(nsMsgDBCommitType::kLargeCommit);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// search sorted table
|
||||
mdb_pos nsMsgDatabase::FindInsertIndexInSortedTable(nsIMdbTable *table, mdb_id idToInsert)
|
||||
{
|
||||
mdb_pos searchPos = 0;
|
||||
PRUint32 rowCount;
|
||||
table->GetCount(GetEnv(), &rowCount);
|
||||
mdb_pos hi = rowCount;
|
||||
mdb_pos lo = 0;
|
||||
|
||||
while (hi > lo)
|
||||
{
|
||||
mdbOid outOid;
|
||||
searchPos = (lo + hi - 1) / 2;
|
||||
table->PosToOid(GetEnv(), searchPos, &outOid);
|
||||
if (outOid.mOid_Id == idToInsert)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "id shouldn't be in table");
|
||||
return hi;
|
||||
}
|
||||
if (outOid.mOid_Id > idToInsert)
|
||||
hi = searchPos;
|
||||
else // if (outOid.mOid_Id < idToInsert)
|
||||
lo = searchPos + 1;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsMsgDatabase::UpdateHdrInCache(const char *aSearchFolderUri, nsIMsgDBHdr *aHdr, PRBool aAdd)
|
||||
{
|
||||
nsCOMPtr <nsIMdbTable> table;
|
||||
nsresult err = GetSearchResultsTable(aSearchFolderUri, PR_TRUE, getter_AddRefs(table));
|
||||
NS_ENSURE_SUCCESS(err, err);
|
||||
nsMsgKey key;
|
||||
aHdr->GetMessageKey(&key);
|
||||
nsMsgHdr* msgHdr = NS_STATIC_CAST(nsMsgHdr*, aHdr); // closed system, so this is ok
|
||||
if (err == NS_OK && m_mdbStore && msgHdr->m_mdbRow)
|
||||
{
|
||||
if (!aAdd)
|
||||
{
|
||||
table->CutRow(m_mdbEnv, msgHdr->m_mdbRow);
|
||||
#ifdef DEBUG_David_Bienvenu
|
||||
printf("removing key %lx \n", key);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
mdbOid rowId;
|
||||
msgHdr->m_mdbRow->GetOid(m_mdbEnv, &rowId);
|
||||
mdb_pos insertPos = FindInsertIndexInSortedTable(table, rowId.mOid_Id);
|
||||
PRUint32 rowCount;
|
||||
table->GetCount(m_mdbEnv, &rowCount);
|
||||
table->AddRow(m_mdbEnv, msgHdr->m_mdbRow);
|
||||
mdb_pos newPos;
|
||||
table->MoveRow(m_mdbEnv, msgHdr->m_mdbRow, rowCount, insertPos, &newPos);
|
||||
#ifdef DEBUG_David_Bienvenu
|
||||
printf("moving row with key %lx to pos %lx \n", key, newPos);
|
||||
// iterate over table and assert that it's in id order
|
||||
table->GetCount(GetEnv(), &rowCount);
|
||||
mdbOid oid;
|
||||
PRUint32 tableRowIndex = 0;
|
||||
mdb_id prevId = 0;
|
||||
while (tableRowIndex < rowCount)
|
||||
{
|
||||
nsresult ret = table->PosToOid (m_mdbEnv, tableRowIndex++, &oid);
|
||||
if (tableRowIndex > 1 && oid.mOid_Id <= prevId)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "inserting row into cached hits table, not sorted correctly");
|
||||
printf("key %lx is before or equal %lx \n", prevId, oid.mOid_Id);
|
||||
}
|
||||
prevId = oid.mOid_Id;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// if (aAdd)
|
||||
// if we need to add this hdr, we need to insert it in key order.
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsMsgDatabase::HdrIsInCache(const char* aSearchFolderUri, nsIMsgDBHdr *aHdr, PRBool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
nsCOMPtr <nsIMdbTable> table;
|
||||
nsresult err = GetSearchResultsTable(aSearchFolderUri, PR_TRUE, getter_AddRefs(table));
|
||||
NS_ENSURE_SUCCESS(err, err);
|
||||
nsMsgKey key;
|
||||
aHdr->GetMessageKey(&key);
|
||||
mdbOid rowObjectId;
|
||||
rowObjectId.mOid_Id = key;
|
||||
rowObjectId.mOid_Scope = m_hdrRowScopeToken;
|
||||
mdb_bool hasOid;
|
||||
err = table->HasOid(GetEnv(), &rowObjectId, &hasOid);
|
||||
*aResult = hasOid;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user