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
|
var treeItem TreeItem
|
||||||
if ti, ok := item.(TreeItem); !ok {
|
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 {
|
if root == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return []uiterm.TreeItem{
|
return []uiterm.TreeItem{TreeItem{Channel: root}}
|
||||||
TreeItem{
|
|
||||||
Channel: root,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
treeItem = ti
|
treeItem = ti
|
||||||
}
|
}
|
||||||
@@ -108,11 +105,17 @@ func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
|
|||||||
|
|
||||||
users := []uiterm.TreeItem{}
|
users := []uiterm.TreeItem{}
|
||||||
ul := []*gumble.User{}
|
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 {
|
for _, user := range treeItem.Channel.Users {
|
||||||
ul = append(ul, user)
|
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 {
|
sort.Slice(ul, func(i, j int) bool {
|
||||||
return ul[i].Name < ul[j].Name
|
return ul[i].Name < ul[j].Name
|
||||||
})
|
})
|
||||||
@@ -123,10 +126,6 @@ func (b *Barnard) TreeItemBuild(item uiterm.TreeItem) []uiterm.TreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channels := []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 {
|
sort.Slice(cl, func(i, j int) bool {
|
||||||
return cl[i].Name < cl[j].Name
|
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