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),
fUIDValidity(UINT32_MAX),
fLastUID(0),
fListener(NULL)
fListener(NULL),
fFolderStateInitialized(false),
fQuitFolderState(false)
{
mutex_init(&fLock, "imap folder lock");
mutex_init(&fFolderStateLock, "imap folder state lock");
}
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)
status = node.SetTo(&ref);
if (status == B_TIMED_OUT)
continue;
if (status == B_TIMED_OUT) {
// We don't know the message state yet
fPendingFlagsMap.insert(std::make_pair(uid, mailboxFlags));
}
if (status != B_OK)
return;
@@ -288,15 +297,32 @@ IMAPFolder::SyncMessageFlags(uint32 uid, uint32 mailboxFlags)
void
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();
for (; iterator != fRefMap.end(); iterator++) {
uint32 uid = iterator->first;
if (fSynchronizedUIDsSet.find(uid) == fSynchronizedUIDsSet.end())
_DeleteLocalMessage(uid);
deleteUIDs.insert(uid);
}
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
IMAPFolder::MessageReceived(BMessage* message)
{
switch (message->what) {
default:
BHandler::MessageReceived(message);
break;
}
}
void
IMAPFolder::_WaitForFolderState()
{
while (true) {
MutexLocker locker(fFolderStateLock);
if (fFolderStateInitialized)
return;
}
}
void
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);
BEntry entry;
while (directory.GetNextEntry(&entry) == B_OK) {
@@ -472,6 +526,8 @@ IMAPFolder::_InitializeFolderState()
uint32 flags = _ReadFlags(node);
MutexLocker locker(fLock);
if (fQuitFolderState)
return;
fRefMap.insert(std::make_pair(uid, ref));
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);
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;
return B_OK;
@@ -98,7 +98,11 @@ public:
virtual void MessageReceived(BMessage* message);
private:
void _WaitForFolderState();
void _InitializeFolderState();
void _ReadFolderState();
static status_t _ReadFolderState(void* self);
const MessageToken _Token(uint32 uid) const;
void _NotifyStoredBody(const entry_ref& ref,
uint32 uid, status_t status);
@@ -150,10 +154,14 @@ private:
uint32 fLastUID;
FolderListener* fListener;
mutex fLock;
bool fInitializing;
mutex fFolderStateLock;
thread_id fReadFolderStateThread;
bool fFolderStateInitialized;
bool fQuitFolderState;
UIDToRefMap fRefMap;
UIDToFlagsMap fFlagsMap;
UIDSet fSynchronizedUIDsSet;
UIDToFlagsMap fPendingFlagsMap;
MessengerMap fPendingBodies;
};