Simplify ring consumer goroutine

Since network.history is now only accessed from the user goroutine, a
lock becomes unnecessary.
This commit is contained in:
Simon Ser 2020-04-01 16:02:31 +02:00
parent 10da094259
commit d4de60a869
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48
2 changed files with 66 additions and 74 deletions

View File

@ -71,6 +71,8 @@ type downstreamConn struct {
password string // empty after authentication password string // empty after authentication
network *network // can be nil network *network // can be nil
ringConsumers map[*network]*RingConsumer
negociatingCaps bool negociatingCaps bool
capVersion int capVersion int
caps map[string]bool caps map[string]bool
@ -90,6 +92,7 @@ func newDownstreamConn(srv *Server, netConn net.Conn, id uint64) *downstreamConn
logger: &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())}, logger: &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())},
outgoing: make(chan *irc.Message, 64), outgoing: make(chan *irc.Message, 64),
closed: make(chan struct{}), closed: make(chan struct{}),
ringConsumers: make(map[*network]*RingConsumer),
caps: make(map[string]bool), caps: make(map[string]bool),
ourMessages: make(map[*irc.Message]struct{}), ourMessages: make(map[*irc.Message]struct{}),
} }
@ -722,9 +725,7 @@ func (dc *downstreamConn) runNetwork(net *network, loadHistory bool) {
var seqPtr *uint64 var seqPtr *uint64
if loadHistory { if loadHistory {
net.lock.Lock()
seq, ok := net.history[dc.clientName] seq, ok := net.history[dc.clientName]
net.lock.Unlock()
if ok { if ok {
seqPtr = &seq seqPtr = &seq
} }
@ -735,20 +736,18 @@ func (dc *downstreamConn) runNetwork(net *network, loadHistory bool) {
serverTimeEnabled := dc.caps["server-time"] serverTimeEnabled := dc.caps["server-time"]
consumer, ch := net.ring.NewConsumer(seqPtr) consumer, ch := net.ring.NewConsumer(seqPtr)
go func() {
for {
var closed bool
select {
case _, ok := <-ch:
if !ok {
closed = true
break
}
if _, ok := dc.ringConsumers[net]; ok {
panic("network has been added twice")
}
dc.ringConsumers[net] = consumer
go func() {
for range ch {
uc := net.upstream() uc := net.upstream()
if uc == nil { if uc == nil {
dc.logger.Printf("ignoring messages for upstream %q: upstream is disconnected", net.Addr) dc.logger.Printf("ignoring messages for upstream %q: upstream is disconnected", net.Addr)
break continue
} }
for { for {
@ -793,21 +792,7 @@ func (dc *downstreamConn) runNetwork(net *network, loadHistory bool) {
dc.SendMessage(msg) dc.SendMessage(msg)
consumer.Consume() consumer.Consume()
} }
case <-dc.closed:
closed = true
} }
if closed {
break
}
}
// TODO: close the consumer from the user goroutine, so we don't need
// that net.history lock
seq := consumer.Close()
net.lock.Lock()
net.history[dc.clientName] = seq
net.lock.Unlock()
}() }()
} }

View File

@ -41,9 +41,10 @@ type network struct {
ring *Ring ring *Ring
stopped chan struct{} stopped chan struct{}
history map[string]uint64
lock sync.Mutex lock sync.Mutex
conn *upstreamConn conn *upstreamConn
history map[string]uint64
} }
func newNetwork(user *user, record *Network) *network { func newNetwork(user *user, record *Network) *network {
@ -235,6 +236,12 @@ func (u *user) run() {
}) })
case eventDownstreamDisconnected: case eventDownstreamDisconnected:
dc := e.dc dc := e.dc
for net, rc := range dc.ringConsumers {
seq := rc.Close()
net.history[dc.clientName] = seq
}
for i := range u.downstreamConns { for i := range u.downstreamConns {
if u.downstreamConns[i] == dc { if u.downstreamConns[i] == dc {
u.downstreamConns = append(u.downstreamConns[:i], u.downstreamConns[i+1:]...) u.downstreamConns = append(u.downstreamConns[:i], u.downstreamConns[i+1:]...)