aboutsummaryrefslogtreecommitdiffstats
path: root/worker
diff options
context:
space:
mode:
authorHugo Osvaldo Barrera <hugo@whynothugo.nl>2024-07-06 23:26:20 +0200
committerRobin Jarry <robin@jarry.cc>2024-08-03 20:09:59 +0200
commitc56649fe5291b725f14b45550a68cc7d0dc16ff7 (patch)
tree7de99e54f982475c0b4a8af58a96a90dde4b06d4 /worker
parent88d5de97d6c2caf37c693a51daf98f81951a37ac (diff)
downloadaerc-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.go15
-rw-r--r--worker/notmuch/worker.go49
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)