aboutsummaryrefslogtreecommitdiffstats
path: root/lib/threadbuilder.go
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2022-11-02 22:26:48 +0100
committerRobin Jarry <robin@jarry.cc>2022-11-06 23:16:23 +0100
commit33ceb56680ba92406137ace7eee8139824446308 (patch)
tree19aa610efe7bbf643ef47525e8a296b4e45b9345 /lib/threadbuilder.go
parent6b0b5596dee5dda9fb367cbf8c82e52b9e6125a3 (diff)
downloadaerc-33ceb56680ba92406137ace7eee8139824446308.tar.gz
threadbuilder: streamline thread builder internals
Streamline the internals of the client-side thread builder. Handle the jwz dummy threads explicitly and let jwz deal with message-id collisions. This should make the client-side threading more stable overall. Duplicated message-ids will also be properly displayed now. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'lib/threadbuilder.go')
-rw-r--r--lib/threadbuilder.go73
1 files changed, 30 insertions, 43 deletions
diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go
index b1609257..52484162 100644
--- a/lib/threadbuilder.go
+++ b/lib/threadbuilder.go
@@ -13,19 +13,15 @@ import (
type ThreadBuilder struct {
sync.Mutex
- threadBlocks map[uint32]jwz.Threadable
- messageidToUid map[string]uint32
- seen map[uint32]bool
- threadedUids []uint32
- iterFactory iterator.Factory
+ threadBlocks map[uint32]jwz.Threadable
+ threadedUids []uint32
+ iterFactory iterator.Factory
}
func NewThreadBuilder(i iterator.Factory) *ThreadBuilder {
tb := &ThreadBuilder{
- threadBlocks: make(map[uint32]jwz.Threadable),
- messageidToUid: make(map[string]uint32),
- seen: make(map[uint32]bool),
- iterFactory: i,
+ threadBlocks: make(map[uint32]jwz.Threadable),
+ iterFactory: i,
}
return tb
}
@@ -48,7 +44,6 @@ func (builder *ThreadBuilder) Update(msg *models.MessageInfo) {
if msg != nil {
if threadable := newThreadable(msg); threadable != nil {
- builder.messageidToUid[threadable.MessageThreadID()] = msg.Uid
builder.threadBlocks[msg.Uid] = threadable
}
}
@@ -70,7 +65,8 @@ func (builder *ThreadBuilder) Threads(uids []uint32, inverse bool) []*types.Thre
builder.RebuildUids(threads, inverse)
elapsed := time.Since(start)
- logging.Infof("%d threads created in %s", len(threads), elapsed)
+ logging.Infof("%d threads from %d uids created in %s", len(threads),
+ len(uids), elapsed)
return threads
}
@@ -98,56 +94,47 @@ func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable, uids []
threads = append(threads, &types.Thread{Uid: uid})
}
} else {
- // fill threads with nil messages
+ // add uids for the unfetched messages
for _, uid := range uids {
if _, ok := builder.threadBlocks[uid]; !ok {
threads = append(threads, &types.Thread{Uid: uid})
}
}
- // append the on-the-fly created aerc threads
+
+ // build thread tree
root := &types.Thread{Uid: 0}
- builder.seen = make(map[uint32]bool)
builder.buildTree(structure, root)
- for iter := root.FirstChild; iter != nil; iter = iter.NextSibling {
- iter.Parent = nil
- threads = append(threads, iter)
+
+ // copy top-level threads to thread slice
+ for thread := root.FirstChild; thread != nil; thread = thread.NextSibling {
+ thread.Parent = nil
+ threads = append(threads, thread)
}
+
}
return threads
}
// buildTree recursively translates the jwz threads structure into aerc threads
-// builder.seen is used to avoid potential double-counting and should be empty
-// on first call of this function
-func (builder *ThreadBuilder) buildTree(treeNode jwz.Threadable, target *types.Thread) {
- if treeNode == nil {
+func (builder *ThreadBuilder) buildTree(c jwz.Threadable, parent *types.Thread) {
+ if c == nil || parent == nil {
return
}
-
- // deal with child
- uid, ok := builder.messageidToUid[treeNode.MessageThreadID()]
- if _, seen := builder.seen[uid]; ok && !seen {
- builder.seen[uid] = true
- childNode := &types.Thread{Uid: uid, Parent: target}
- target.OrderedInsert(childNode)
- builder.buildTree(treeNode.GetChild(), childNode)
- } else {
- builder.buildTree(treeNode.GetChild(), target)
+ for node := c; node != nil; node = node.GetNext() {
+ thread := parent
+ if !node.IsDummy() {
+ thread = builder.newThread(node, parent)
+ parent.OrderedInsert(thread)
+ }
+ builder.buildTree(node.GetChild(), thread)
}
+}
- // deal with siblings
- for next := treeNode.GetNext(); next != nil; next = next.GetNext() {
-
- uid, ok := builder.messageidToUid[next.MessageThreadID()]
- if _, seen := builder.seen[uid]; ok && !seen {
- builder.seen[uid] = true
- nn := &types.Thread{Uid: uid, Parent: target}
- target.OrderedInsert(nn)
- builder.buildTree(next.GetChild(), nn)
- } else {
- builder.buildTree(next.GetChild(), target)
- }
+func (builder *ThreadBuilder) newThread(c jwz.Threadable, parent *types.Thread) *types.Thread {
+ if threadable, ok := c.(*threadable); ok {
+ return &types.Thread{Uid: threadable.MsgInfo.Uid, Parent: parent}
}
+ return nil
}
func (builder *ThreadBuilder) sortThreads(threads []*types.Thread, orderedUids []uint32) {