From 5c58089fb7b1c88fa5cfbb7cc877a2675eb6941b Mon Sep 17 00:00:00 2001 From: Michal Horejsek Date: Mon, 7 Dec 2020 14:14:45 +0100 Subject: [PATCH] Do not unpause event loop if other mailbox is still fetching --- internal/imap/mailbox_messages.go | 4 ++-- internal/imap/user.go | 38 +++++++++++++++++++++++++++---- unreleased.md | 1 + 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/internal/imap/mailbox_messages.go b/internal/imap/mailbox_messages.go index 232dc114..c52fdf18 100644 --- a/internal/imap/mailbox_messages.go +++ b/internal/imap/mailbox_messages.go @@ -454,8 +454,8 @@ func (im *imapMailbox) ListMessages(isUID bool, seqSet *imap.SeqSet, items []ima // EXPUNGE cannot be sent during listing and can come only from // the event loop, so we prevent any server side update to avoid // the problem. - im.storeUser.PauseEventLoop(true) - defer im.storeUser.PauseEventLoop(false) + im.user.pauseEventLoop() + defer im.user.unpauseEventLoop() var markAsReadIDs []string markAsReadMutex := &sync.Mutex{} diff --git a/internal/imap/user.go b/internal/imap/user.go index 5647b14c..a4c72842 100644 --- a/internal/imap/user.go +++ b/internal/imap/user.go @@ -42,11 +42,9 @@ type imapUser struct { currentAddressLowercase string appendInProcess sync.WaitGroup -} -// This method should eventually no longer be necessary. Everything should go via store. -func (iu *imapUser) client() pmapi.Client { - return iu.user.GetTemporaryPMAPIClient() + eventLoopPausingCounter int + eventLoopPausingLocker sync.Locker } // newIMAPUser returns struct implementing go-imap/user interface. @@ -78,9 +76,41 @@ func newIMAPUser( storeAddress: storeAddress, currentAddressLowercase: strings.ToLower(address), + + eventLoopPausingLocker: &sync.Mutex{}, }, err } +// This method should eventually no longer be necessary. Everything should go via store. +func (iu *imapUser) client() pmapi.Client { + return iu.user.GetTemporaryPMAPIClient() +} + +// pauseEventLoop pauses event loop and increases the number of mailboxes which +// is performing action forbidding event loop to run (such as FETCH which needs +// UIDs to be stable and thus EXPUNGE cannot be done during the request). +func (iu *imapUser) pauseEventLoop() { + iu.eventLoopPausingLocker.Lock() + defer iu.eventLoopPausingLocker.Unlock() + + iu.eventLoopPausingCounter++ + iu.storeUser.PauseEventLoop(true) +} + +// unpauseEventLoop unpauses event loop but only if no other request is not +// performing action forbidding event loop to run (see pauseEventLoop). +func (iu *imapUser) unpauseEventLoop() { + iu.eventLoopPausingLocker.Lock() + defer iu.eventLoopPausingLocker.Unlock() + + if iu.eventLoopPausingCounter > 0 { + iu.eventLoopPausingCounter-- + } + if iu.eventLoopPausingCounter == 0 { + iu.storeUser.PauseEventLoop(false) + } +} + func (iu *imapUser) isSubscribed(labelID string) bool { subscriptionExceptions := iu.backend.getCacheList(iu.storeUser.UserID(), SubscriptionException) exceptions := strings.Split(subscriptionExceptions, ";") diff --git a/unreleased.md b/unreleased.md index 30833ccc..e47b6b63 100644 --- a/unreleased.md +++ b/unreleased.md @@ -52,3 +52,4 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ### Fixed * GODT-900 Remove \Deleted flag after re-importing the message (do not delete messages by moving to local folder and back). +* GODT-908 Do not unpause event loop if other mailbox is still fetching.