Snapshot channel tree maps under client lock
This commit is contained in:
committed by
Brandon McGinty
parent
4fe32ede70
commit
f629ce0359
+11
-12
@@ -89,15 +89,12 @@ func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
|
||||
|
||||
var treeItem TreeItem
|
||||
if ti, ok := item.(TreeItem); !ok {
|
||||
root := b.Client.Channels[0]
|
||||
var root *gumble.Channel
|
||||
b.Client.Do(func() { root = b.Client.Channels[0] })
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
return []uiterm.TreeItem{
|
||||
TreeItem{
|
||||
Channel: root,
|
||||
},
|
||||
}
|
||||
return []uiterm.TreeItem{TreeItem{Channel: root}}
|
||||
} else {
|
||||
treeItem = ti
|
||||
}
|
||||
@@ -108,11 +105,17 @@ func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
|
||||
|
||||
users := []uiterm.TreeItem{}
|
||||
ul := []*gumble.User{}
|
||||
cl := []*gumble.Channel{}
|
||||
// TCP handlers mutate both maps; snapshot them while Client.Do holds its
|
||||
// read lock, then sort/render outside the protocol critical section.
|
||||
b.Client.Do(func() {
|
||||
for _, user := range treeItem.Channel.Users {
|
||||
ul = append(ul, user)
|
||||
var u = ul[len(ul)-1]
|
||||
_ = u
|
||||
}
|
||||
for _, subchannel := range treeItem.Channel.Children {
|
||||
cl = append(cl, subchannel)
|
||||
}
|
||||
})
|
||||
sort.Slice(ul, func(i, j int) bool {
|
||||
return ul[i].Name < ul[j].Name
|
||||
})
|
||||
@@ -123,10 +126,6 @@ func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
|
||||
}
|
||||
|
||||
channels := []uiterm.TreeItem{}
|
||||
cl := []*gumble.Channel{}
|
||||
for _, subchannel := range treeItem.Channel.Children {
|
||||
cl = append(cl, subchannel)
|
||||
}
|
||||
sort.Slice(cl, func(i, j int) bool {
|
||||
return cl[i].Name < cl[j].Name
|
||||
})
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/barnard/gumble/gumble"
|
||||
)
|
||||
|
||||
// Regression: rebuilding the channel tree ranged protocol-owned maps without
|
||||
// Client.Do while TCP handlers could add or remove users/channels.
|
||||
func TestTreeItemBuildReadsMapsUnderClientSnapshot(t *testing.T) {
|
||||
root := &gumble.Channel{ID: 0, Users: gumble.Users{}, Children: gumble.Channels{}}
|
||||
user := &gumble.User{Session: 1, Name: "user"}
|
||||
child := &gumble.Channel{ID: 2, Name: "child", Users: gumble.Users{}, Children: gumble.Channels{}}
|
||||
root.Users[user.Session] = user
|
||||
root.Children[child.ID] = child
|
||||
b := &Barnard{Client: &gumble.Client{Channels: gumble.Channels{0: root}}, MutedChannels: map[uint32]bool{}}
|
||||
items := b.TreeItemBuild(TreeItem{Channel: root})
|
||||
if len(items) != 2 {
|
||||
t.Fatalf("got %d items", len(items))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user