mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-18 02:48:40 +00:00
derp: remove stats goroutine, use a timer
Without changing behaviour, don't create a goroutine per connection that sits and sleeps, but rather use a timer that wakes up and gathers statistics on a regular basis. Fixes #12127 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Ibc486447e403070bdc3c2cd8ae340e7d02854f21
This commit is contained in:
parent
7ef2f72135
commit
c6d42b1093
@ -776,7 +776,6 @@ func (c *sclient) run(ctx context.Context) error {
|
||||
var grp errgroup.Group
|
||||
sendCtx, cancelSender := context.WithCancel(ctx)
|
||||
grp.Go(func() error { return c.sendLoop(sendCtx) })
|
||||
grp.Go(func() error { return c.statsLoop(sendCtx) })
|
||||
defer func() {
|
||||
cancelSender()
|
||||
if err := grp.Wait(); err != nil && !c.s.isClosed() {
|
||||
@ -788,6 +787,8 @@ func (c *sclient) run(ctx context.Context) error {
|
||||
}
|
||||
}()
|
||||
|
||||
c.startStatsLoop(sendCtx)
|
||||
|
||||
for {
|
||||
ft, fl, err := readFrameHeader(c.br)
|
||||
c.debugLogf("read frame type %d len %d err %v", ft, fl, err)
|
||||
|
@ -7,6 +7,7 @@ package derp
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *sclient) statsLoop(ctx context.Context) error {
|
||||
return nil
|
||||
func (c *sclient) startStatsLoop(ctx context.Context) {
|
||||
// Nothing to do
|
||||
return
|
||||
}
|
||||
|
@ -12,40 +12,43 @@ import (
|
||||
"tailscale.com/net/tcpinfo"
|
||||
)
|
||||
|
||||
func (c *sclient) statsLoop(ctx context.Context) error {
|
||||
func (c *sclient) startStatsLoop(ctx context.Context) {
|
||||
// Get the RTT initially to verify it's supported.
|
||||
conn := c.tcpConn()
|
||||
if conn == nil {
|
||||
c.s.tcpRtt.Add("non-tcp", 1)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if _, err := tcpinfo.RTT(conn); err != nil {
|
||||
c.logf("error fetching initial RTT: %v", err)
|
||||
c.s.tcpRtt.Add("error", 1)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
const statsInterval = 10 * time.Second
|
||||
|
||||
ticker, tickerChannel := c.s.clock.NewTicker(statsInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
statsLoop:
|
||||
for {
|
||||
select {
|
||||
case <-tickerChannel:
|
||||
rtt, err := tcpinfo.RTT(conn)
|
||||
if err != nil {
|
||||
continue statsLoop
|
||||
}
|
||||
|
||||
// TODO(andrew): more metrics?
|
||||
c.s.tcpRtt.Add(durationToLabel(rtt), 1)
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
// Don't launch a goroutine; use a timer instead.
|
||||
var gatherStats func()
|
||||
gatherStats = func() {
|
||||
// Do nothing if the context is finished.
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Reschedule ourselves when this stats gathering is finished.
|
||||
defer c.s.clock.AfterFunc(statsInterval, gatherStats)
|
||||
|
||||
// Gather TCP RTT information.
|
||||
rtt, err := tcpinfo.RTT(conn)
|
||||
if err == nil {
|
||||
c.s.tcpRtt.Add(durationToLabel(rtt), 1)
|
||||
}
|
||||
|
||||
// TODO(andrew): more metrics?
|
||||
}
|
||||
|
||||
// Kick off the initial timer.
|
||||
c.s.clock.AfterFunc(statsInterval, gatherStats)
|
||||
}
|
||||
|
||||
// tcpConn attempts to get the underlying *net.TCPConn from this client's
|
||||
|
Loading…
x
Reference in New Issue
Block a user