perf: sync dispatch hot path optimizations

This commit is contained in:
A 2026-07-06 14:27:03 +08:00
parent 03b785ebf4
commit 7e64d9c30e
13 changed files with 824 additions and 215 deletions

View file

@ -1,6 +1,7 @@
package mtprotoedge
import (
"bufio"
"context"
"crypto/aes"
"errors"
@ -165,34 +166,40 @@ func (c *Conn) sendBestEffort(ctx context.Context, t proto.MessageType, msg bin.
encoded: encoded,
enqueuedAt: time.Now(),
}
// 快路径非阻塞入队。fan-out 每 (conn × push) 都走这里,队列有空位时不为
// 本次推送分配任何 timer此前 timeout>0 无条件 WithTimeout稳态白建 timer
select {
case c.outbound <- op:
return nil
case <-c.outboundStop:
return ErrConnClosed
default:
}
if timeout == 0 {
select {
case c.outbound <- op:
return nil
case <-c.outboundStop:
return ErrConnClosed
default:
c.metrics.OutboundDropped("push_queue_full")
return ErrOutboundQueueFull
}
c.metrics.OutboundDropped("push_queue_full")
return ErrOutboundQueueFull
}
enqueueCtx := ctx
if enqueueCtx == nil {
enqueueCtx = context.Background()
c.metrics.OutboundQueueWait(len(c.outbound), cap(c.outbound))
if ctx == nil {
ctx = context.Background()
}
var cancel context.CancelFunc
var timeoutC <-chan time.Time
if timeout > 0 {
enqueueCtx, cancel = context.WithTimeout(enqueueCtx, timeout)
defer cancel()
timer := time.NewTimer(timeout)
defer timer.Stop()
timeoutC = timer.C
}
if err := c.enqueueOutbound(enqueueCtx, op); err != nil {
if errors.Is(err, context.DeadlineExceeded) && timeout > 0 {
c.metrics.OutboundDropped("push_queue_timeout")
return ErrOutboundQueueFull
}
return err
select {
case c.outbound <- op:
return nil
case <-timeoutC:
c.metrics.OutboundDropped("push_queue_timeout")
return ErrOutboundQueueFull
case <-ctx.Done():
return ctx.Err()
case <-c.outboundStop:
return ErrConnClosed
}
return nil
}
func (c *Conn) send(ctx context.Context, t proto.MessageType, msg bin.Encoder, control bool) error {
@ -600,6 +607,13 @@ func (c *Conn) commitContentSeqNo() {
c.sentContentMessages++
}
// deadlineOutboundWriter 是可选的直管写超时接口telesrv-owned compat transport 实现它,
// 让 outbound actor 每帧只做一次 SetWriteDeadline不再为写超时分配 context timer
// gotd transport.Conn 的 Send 本身也只消费 ctx.Deadline不监听 ctx.Done语义等价
type deadlineOutboundWriter interface {
SendDeadline(deadline time.Time, b *bin.Buffer) error
}
func (c *Conn) writeFrame(ctx context.Context, frame *outboundFrame) error {
if ctx == nil {
ctx = context.Background()
@ -609,17 +623,30 @@ func (c *Conn) writeFrame(ctx context.Context, frame *outboundFrame) error {
return fmt.Errorf("encrypt: %w", err)
}
sendCtx := ctx
cancel := func() {}
if c.writeTimeout > 0 {
sendCtx, cancel = context.WithTimeout(ctx, c.writeTimeout)
}
defer cancel()
writer := c.writer
if writer == nil {
writer = c.transport
}
if err := writer.Send(sendCtx, out); err != nil {
var deadline time.Time
if c.writeTimeout > 0 {
deadline = time.Now().Add(c.writeTimeout)
}
if d, ok := ctx.Deadline(); ok && (deadline.IsZero() || d.Before(deadline)) {
deadline = d
}
if dw, ok := writer.(deadlineOutboundWriter); ok {
err = dw.SendDeadline(deadline, out)
} else {
// 回落路径gotd full codec / 测试注入 codec 仍走 ctx deadline。
sendCtx := ctx
cancel := func() {}
if !deadline.IsZero() {
sendCtx, cancel = context.WithDeadline(ctx, deadline)
}
err = writer.Send(sendCtx, out)
cancel()
}
if err != nil {
return fmt.Errorf("send: %w", err)
}
if frame.sentAt.IsZero() {
@ -642,7 +669,13 @@ func (c *Conn) encryptOutboundFrame(frame *outboundFrame) (*bin.Buffer, error) {
paddingOffset := plain.Len()
paddingLen := encryptedPaddingLen(paddingOffset)
growBinBufferLen(plain, paddingOffset+paddingLen)
if _, err := io.ReadFull(c.cipher.Rand(), plain.Buf[paddingOffset:]); err != nil {
// padding 随机数走 per-Conn 缓冲读:每帧 12..1024 字节直读 crypto/rand 是一次
// getrandom syscall缓冲后按 ~1KiB 批量取。只由 outbound actor 单 goroutine 访问,
// 随机源本身不变(仍是 cipher 的 CSPRNG只是预读。
if c.outboundRand == nil {
c.outboundRand = bufio.NewReaderSize(c.cipher.Rand(), 1024)
}
if _, err := io.ReadFull(c.outboundRand, plain.Buf[paddingOffset:]); err != nil {
return nil, err
}