From a275f65848f2c1fdd4302f56121defc408e7d8b6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 28 Apr 2019 13:26:38 +0000 Subject: lib/msgstore: protect with a mutex MessageStore has a lot of exported fields that can be read from the outside. Each read must be protected, because a call from Update could happen at any time. --- lib/msgstore.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/msgstore.go b/lib/msgstore.go index 9d537fc..b39d0bb 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -2,6 +2,7 @@ package lib import ( "io" + "sync" "time" "github.com/emersion/go-imap" @@ -9,7 +10,10 @@ import ( "git.sr.ht/~sircmpwn/aerc2/worker/types" ) +// Accesses to fields must be guarded by MessageStore.Lock/Unlock type MessageStore struct { + sync.Mutex + Deleted map[uint32]interface{} DirInfo types.DirectoryInfo Messages map[uint32]*types.MessageInfo @@ -45,6 +49,9 @@ func NewMessageStore(worker *types.Worker, func (store *MessageStore) FetchHeaders(uids []uint32, cb func(*types.MessageInfo)) { + store.Lock() + defer store.Unlock() + // TODO: this could be optimized by pre-allocating toFetch and trimming it // at the end. In practice we expect to get most messages back in one frame. var toFetch imap.SeqSet @@ -67,6 +74,9 @@ func (store *MessageStore) FetchHeaders(uids []uint32, } func (store *MessageStore) FetchFull(uids []uint32, cb func(io.Reader)) { + store.Lock() + defer store.Unlock() + // TODO: this could be optimized by pre-allocating toFetch and trimming it // at the end. In practice we expect to get most messages back in one frame. var toFetch imap.SeqSet @@ -103,8 +113,7 @@ func (store *MessageStore) FetchBodyPart( }) } -func (store *MessageStore) merge( - to *types.MessageInfo, from *types.MessageInfo) { +func merge(to *types.MessageInfo, from *types.MessageInfo) { if from.BodyStructure != nil { to.BodyStructure = from.BodyStructure @@ -125,6 +134,8 @@ func (store *MessageStore) merge( } func (store *MessageStore) Update(msg types.WorkerMessage) { + store.Lock() + update := false switch msg := msg.(type) { case *types.DirectoryInfo: @@ -144,7 +155,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { update = true case *types.MessageInfo: if existing, ok := store.Messages[msg.Uid]; ok && existing != nil { - store.merge(existing, msg) + merge(existing, msg) } else { store.Messages[msg.Uid] = msg } @@ -186,6 +197,9 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { store.Uids = uids update = true } + + store.Unlock() + if update { store.update() } @@ -202,11 +216,16 @@ func (store *MessageStore) update() { } func (store *MessageStore) Delete(uids []uint32) { + store.Lock() + var set imap.SeqSet for _, uid := range uids { set.AddNum(uid) store.Deleted[uid] = nil } + + store.Unlock() + store.worker.PostAction(&types.DeleteMessages{Uids: set}, nil) store.update() } -- cgit v1.2.3