tx_batch.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package batch
  2. import "net/netip"
  3. const SendBatchCap = 128
  4. // batchWriter is the minimal subset of udp.Conn needed by SendBatch to flush.
  5. type batchWriter interface {
  6. WriteBatch(bufs [][]byte, addrs []netip.AddrPort, outerECNs []byte) error
  7. }
  8. // SendBatch accumulates encrypted UDP packets and flushes them via WriteBatch.
  9. // One SendBatch is owned by each listenIn goroutine; no locking is needed.
  10. // Slots are backed by an Arena (see its docs)
  11. type SendBatch struct {
  12. out batchWriter
  13. bufs [][]byte
  14. dsts []netip.AddrPort
  15. ecns []byte
  16. arena *Arena
  17. }
  18. // NewSendBatch makes a SendBatch with batchCap slots and an arenaSize byte buffer for slices to back those slots
  19. func NewSendBatch(out batchWriter, batchCap, arenaSize int) *SendBatch {
  20. return &SendBatch{
  21. out: out,
  22. bufs: make([][]byte, 0, batchCap),
  23. dsts: make([]netip.AddrPort, 0, batchCap),
  24. ecns: make([]byte, 0, batchCap),
  25. arena: NewArena(arenaSize),
  26. }
  27. }
  28. func (b *SendBatch) Reserve(sz int) []byte {
  29. return b.arena.Reserve(sz)
  30. }
  31. // Len reports how many packets are queued for the next Flush. Callers use
  32. // it to flush incrementally once a full sendmmsg batch has accumulated,
  33. // bounding how long the first packet of a large read batch waits.
  34. func (b *SendBatch) Len() int { return len(b.bufs) }
  35. func (b *SendBatch) Commit(pkt []byte, dst netip.AddrPort, outerECN byte) {
  36. b.bufs = append(b.bufs, pkt)
  37. b.dsts = append(b.dsts, dst)
  38. b.ecns = append(b.ecns, outerECN)
  39. }
  40. func (b *SendBatch) Flush() error {
  41. var err error
  42. if len(b.bufs) > 0 {
  43. err = b.out.WriteBatch(b.bufs, b.dsts, b.ecns)
  44. }
  45. clear(b.bufs)
  46. b.bufs = b.bufs[:0]
  47. b.dsts = b.dsts[:0]
  48. b.ecns = b.ecns[:0]
  49. b.arena.Reset()
  50. return err
  51. }