diff options
author | Hugo Osvaldo Barrera <hugo@whynothugo.nl> | 2024-07-06 23:26:20 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-08-03 20:09:59 +0200 |
commit | c56649fe5291b725f14b45550a68cc7d0dc16ff7 (patch) | |
tree | 7de99e54f982475c0b4a8af58a96a90dde4b06d4 /worker | |
parent | 88d5de97d6c2caf37c693a51daf98f81951a37ac (diff) | |
download | aerc-c56649fe5291b725f14b45550a68cc7d0dc16ff7.tar.gz |
notmuch: don't reload all message on change
When a notmuch query result was shown and any message changes (e.g.: was
marked as read, deleted, flagged, etc) the entire result set was
reloaded from disk. This included querying the notmuch for paths for
each file individually and then reading headers from each file one by
one.
If the current view was a query-map with 4000 results, then marking a
single message as read resulted in 4000 files being read from disk.
When a change is detected in the database, instead of sending an
individual MessageInfo event for each message in the result set, send a
single DirectoryContents event. The UI code will remove from view any
messages that no longer exist, add new ones and request from the worker
any data that may be required (this data will be lazy-fetched).
This results in a dramatic performance improvement when reading messages
from a query-map result. Previously reading a single message would
result in about 2 minutes of CPU at 150% (on a i7-13700K). With this
patch, the same operation uses less than 5% CPU for less than 2 seconds.
Signed-off-by: Hugo Osvaldo Barrera <hugo@whynothugo.nl>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'worker')
-rw-r--r-- | worker/notmuch/eventhandlers.go | 15 | ||||
-rw-r--r-- | worker/notmuch/worker.go | 49 |
2 files changed, 23 insertions, 41 deletions
diff --git a/worker/notmuch/eventhandlers.go b/worker/notmuch/eventhandlers.go index 76517953..db490949 100644 --- a/worker/notmuch/eventhandlers.go +++ b/worker/notmuch/eventhandlers.go @@ -9,7 +9,6 @@ import ( "path/filepath" "strconv" - "git.sr.ht/~rjarry/aerc/lib/log" "git.sr.ht/~rjarry/aerc/worker/types" ) @@ -76,17 +75,9 @@ func (w *worker) updateChangedMessages() error { if err != nil { return fmt.Errorf("Couldn't get updates messages: %w", err) } - for _, uid := range uids { - m, err := w.msgFromUid(uid) - if err != nil { - log.Errorf("%s", err) - continue - } - err = w.emitMessageInfo(m, nil) - if err != nil { - log.Errorf("%s", err) - } - } + w.w.PostMessage(&types.DirectoryContents{ + Uids: uids, + }, nil) w.state = newState return nil } diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go index a36b44d4..2a11c1df 100644 --- a/worker/notmuch/worker.go +++ b/worker/notmuch/worker.go @@ -432,12 +432,30 @@ func (w *worker) handleFetchMessageHeaders( w.emitMessageInfoError(msg, uid, err) continue } - err = w.emitMessageInfo(m, msg) + info, err := m.MessageInfo() if err != nil { - w.w.Errorf("could not emit message info: %v", err) w.emitMessageInfoError(msg, uid, err) continue } + switch { + case len(w.headersExclude) > 0: + info.RFC822Headers = lib.LimitHeaders(info.RFC822Headers, w.headersExclude, true) + case len(w.headers) > 0: + info.RFC822Headers = lib.LimitHeaders(info.RFC822Headers, w.headers, false) + } + + switch msg { + case nil: + w.w.PostMessage(&types.MessageInfo{ + Info: info, + }, nil) + default: + w.w.PostMessage(&types.MessageInfo{ + Message: types.RespondTo(msg), + Info: info, + }, nil) + } + } w.done(msg) return nil @@ -679,33 +697,6 @@ func (w *worker) emitMessageInfoError(msg types.WorkerMessage, uid uint32, err e }, nil) } -func (w *worker) emitMessageInfo(m *Message, - parent types.WorkerMessage, -) error { - info, err := m.MessageInfo() - if err != nil { - return fmt.Errorf("could not get MessageInfo: %w", err) - } - switch { - case len(w.headersExclude) > 0: - info.RFC822Headers = lib.LimitHeaders(info.RFC822Headers, w.headersExclude, true) - case len(w.headers) > 0: - info.RFC822Headers = lib.LimitHeaders(info.RFC822Headers, w.headers, false) - } - switch parent { - case nil: - w.w.PostMessage(&types.MessageInfo{ - Info: info, - }, nil) - default: - w.w.PostMessage(&types.MessageInfo{ - Message: types.RespondTo(parent), - Info: info, - }, nil) - } - return nil -} - func (w *worker) emitLabelList() { tags := w.db.ListTags() w.w.PostMessage(&types.LabelList{Labels: tags}, nil) |