IMAP: Retrieve on-disk folder state async.

* Messages that we don't have info for during synchronization are now
  collected, and synchronized once the folder state is available,
  instead of waiting for that particular entry to become available
  (without proper means to wait).
This commit is contained in:
Axel Dörfler
2016-02-10 13:55:55 +01:00
parent 1870a4b1f9
commit 15216b261a
2 changed files with 82 additions and 9 deletions
@@ -93,14 +93,21 @@ IMAPFolder::IMAPFolder(IMAPProtocol& protocol, const BString& mailboxName,
fMailboxName(mailboxName), fMailboxName(mailboxName),
fUIDValidity(UINT32_MAX), fUIDValidity(UINT32_MAX),
fLastUID(0), fLastUID(0),
fListener(NULL) fListener(NULL),
fFolderStateInitialized(false),
fQuitFolderState(false)
{ {
mutex_init(&fLock, "imap folder lock"); mutex_init(&fLock, "imap folder lock");
mutex_init(&fFolderStateLock, "imap folder state lock");
} }
IMAPFolder::~IMAPFolder() IMAPFolder::~IMAPFolder()
{ {
if (!fFolderStateInitialized) {
fQuitFolderState = true;
wait_for_thread(fReadFolderStateThread, NULL);
}
} }
@@ -245,8 +252,10 @@ IMAPFolder::SyncMessageFlags(uint32 uid, uint32 mailboxFlags)
} }
if (status == B_OK) if (status == B_OK)
status = node.SetTo(&ref); status = node.SetTo(&ref);
if (status == B_TIMED_OUT) if (status == B_TIMED_OUT) {
continue; // We don't know the message state yet
fPendingFlagsMap.insert(std::make_pair(uid, mailboxFlags));
}
if (status != B_OK) if (status != B_OK)
return; return;
@@ -288,15 +297,32 @@ IMAPFolder::SyncMessageFlags(uint32 uid, uint32 mailboxFlags)
void void
IMAPFolder::MessageEntriesFetched() IMAPFolder::MessageEntriesFetched()
{ {
// Delete all local messages that weren't synchronized with the server _WaitForFolderState();
// Synchronize all pending flags first
UIDToFlagsMap::const_iterator pendingIterator = fPendingFlagsMap.begin();
for (; pendingIterator != fPendingFlagsMap.end(); pendingIterator++)
SyncMessageFlags(pendingIterator->first, pendingIterator->second);
fPendingFlagsMap.clear();
// Delete all local messages that are no longer found on the server
MutexLocker locker(fLock);
UIDSet deleteUIDs;
UIDToRefMap::const_iterator iterator = fRefMap.begin(); UIDToRefMap::const_iterator iterator = fRefMap.begin();
for (; iterator != fRefMap.end(); iterator++) { for (; iterator != fRefMap.end(); iterator++) {
uint32 uid = iterator->first; uint32 uid = iterator->first;
if (fSynchronizedUIDsSet.find(uid) == fSynchronizedUIDsSet.end()) if (fSynchronizedUIDsSet.find(uid) == fSynchronizedUIDsSet.end())
_DeleteLocalMessage(uid); deleteUIDs.insert(uid);
} }
fSynchronizedUIDsSet.clear(); fSynchronizedUIDsSet.clear();
locker.Unlock();
UIDSet::const_iterator deleteIterator = deleteUIDs.begin();
for (; deleteIterator != deleteUIDs.end(); deleteIterator++)
_DeleteLocalMessage(*deleteIterator);
} }
@@ -446,14 +472,42 @@ IMAPFolder::DeleteMessage(uint32 uid)
void void
IMAPFolder::MessageReceived(BMessage* message) IMAPFolder::MessageReceived(BMessage* message)
{ {
switch (message->what) {
default:
BHandler::MessageReceived(message);
break;
}
}
void
IMAPFolder::_WaitForFolderState()
{
while (true) {
MutexLocker locker(fFolderStateLock);
if (fFolderStateInitialized)
return;
}
} }
void void
IMAPFolder::_InitializeFolderState() IMAPFolder::_InitializeFolderState()
{ {
fInitializing = true; mutex_lock(&fFolderStateLock);
fReadFolderStateThread = spawn_thread(&IMAPFolder::_ReadFolderState,
"IMAP folder state", B_NORMAL_PRIORITY, this);
if (fReadFolderStateThread >= 0)
resume_thread(fReadFolderStateThread);
else
mutex_unlock(&fFolderStateLock);
}
void
IMAPFolder::_ReadFolderState()
{
BDirectory directory(&fRef); BDirectory directory(&fRef);
BEntry entry; BEntry entry;
while (directory.GetNextEntry(&entry) == B_OK) { while (directory.GetNextEntry(&entry) == B_OK) {
@@ -472,6 +526,8 @@ IMAPFolder::_InitializeFolderState()
uint32 flags = _ReadFlags(node); uint32 flags = _ReadFlags(node);
MutexLocker locker(fLock); MutexLocker locker(fLock);
if (fQuitFolderState)
return;
fRefMap.insert(std::make_pair(uid, ref)); fRefMap.insert(std::make_pair(uid, ref));
fFlagsMap.insert(std::make_pair(uid, flags)); fFlagsMap.insert(std::make_pair(uid, flags));
@@ -497,7 +553,16 @@ IMAPFolder::_InitializeFolderState()
// //
} }
fInitializing = false; fFolderStateInitialized = true;
mutex_unlock(&fFolderStateLock);
}
/*static*/ status_t
IMAPFolder::_ReadFolderState(void* self)
{
((IMAPFolder*)self)->_ReadFolderState();
return B_OK;
} }
@@ -535,7 +600,7 @@ IMAPFolder::_GetMessageEntryRef(uint32 uid, entry_ref& ref) const
{ {
UIDToRefMap::const_iterator found = fRefMap.find(uid); UIDToRefMap::const_iterator found = fRefMap.find(uid);
if (found == fRefMap.end()) if (found == fRefMap.end())
return fInitializing ? B_TIMED_OUT : B_ENTRY_NOT_FOUND; return !fFolderStateInitialized ? B_TIMED_OUT : B_ENTRY_NOT_FOUND;
ref = found->second; ref = found->second;
return B_OK; return B_OK;
@@ -98,7 +98,11 @@ public:
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
private: private:
void _WaitForFolderState();
void _InitializeFolderState(); void _InitializeFolderState();
void _ReadFolderState();
static status_t _ReadFolderState(void* self);
const MessageToken _Token(uint32 uid) const; const MessageToken _Token(uint32 uid) const;
void _NotifyStoredBody(const entry_ref& ref, void _NotifyStoredBody(const entry_ref& ref,
uint32 uid, status_t status); uint32 uid, status_t status);
@@ -150,10 +154,14 @@ private:
uint32 fLastUID; uint32 fLastUID;
FolderListener* fListener; FolderListener* fListener;
mutex fLock; mutex fLock;
bool fInitializing; mutex fFolderStateLock;
thread_id fReadFolderStateThread;
bool fFolderStateInitialized;
bool fQuitFolderState;
UIDToRefMap fRefMap; UIDToRefMap fRefMap;
UIDToFlagsMap fFlagsMap; UIDToFlagsMap fFlagsMap;
UIDSet fSynchronizedUIDsSet; UIDSet fSynchronizedUIDsSet;
UIDToFlagsMap fPendingFlagsMap;
MessengerMap fPendingBodies; MessengerMap fPendingBodies;
}; };