receive

package
v0.0.0-...-c77258e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package receive implements the receiver-side congestion control for SRT live mode.

Debug Stub (Release Build)

This file provides no-op implementations of debug assertions for release builds. All functions compile to nothing, incurring zero runtime overhead.

For debug builds with actual assertions, build with: go build -tags debug

Reference: lockless_sender_implementation_plan.md Step 7.5.2

Index

Constants

View Source
const (
	// InterPacketIntervalMinUs filters out measurement errors (sub-10µs intervals).
	InterPacketIntervalMinUs = 10

	// InterPacketIntervalMaxUs filters out pauses (>100ms gaps aren't normal inter-packet).
	InterPacketIntervalMaxUs = 100_000

	// InterPacketIntervalDefaultUs is the fallback when no measurement available (1ms = ~1000pps).
	InterPacketIntervalDefaultUs = 1000

	// InterPacketEWMAAlpha is the weight for new samples (0.125 = 1/8).
	// Old = 0.875, New = 0.125 provides smooth convergence.
	InterPacketEWMAAlpha = 0.125
)
View Source
const DefaultNakConsolidationBudgetUs = 2_000 // 2ms in microseconds

DefaultNakConsolidationBudgetUs is the default time budget for NAK consolidation (2ms). This should be sufficient for consolidating thousands of NAK entries under normal conditions. If consolidation routinely exceeds this budget, it indicates a performance problem.

View Source
const DefaultPayloadSizeBytes = 1456

Variables

This section is empty.

Functions

func CalcTooRecentThreshold

func CalcTooRecentThreshold(now uint64, tsbpdDelay uint64, nakRecentPercent float64) uint64

CalcTooRecentThreshold calculates the TSBPD threshold for "too recent" packets. Packets with PktTsbpdTime > threshold are considered "too recent" to NAK (they might still arrive out-of-order, not actually lost).

Formula: threshold = now + tsbpdDelay * (1.0 - nakRecentPercent)

With nakRecentPercent = 0.10 (10%):

threshold = now + tsbpdDelay * 0.90

Derivation:

  • A packet with PktTsbpdTime = T arrived at (T - tsbpdDelay)
  • We wait nakRecentPercent (10%) of TSBPD after arrival before NAKing
  • So we NAK when: now >= (T - tsbpdDelay) + tsbpdDelay * nakRecentPercent
  • Rearranging: T <= now + tsbpdDelay * (1.0 - nakRecentPercent)
  • Packets with T > threshold are "too recent"

Example with tsbpdDelay=3s, nakRecentPercent=0.10:

  • threshold = now + 2.7s
  • Packets with TSBPD within 2.7s of now are scannable
  • Packets with TSBPD more than 2.7s in the future are "too recent"

This function is exported for unit testing.

func New

func New(recvConfig Config) congestion.Receiver

New takes a Config and returns a new Receiver.

func NewBTreePacketStore

func NewBTreePacketStore(degree int) packetStore

NewBTreePacketStore creates a new btree-based packet store

func NewListPacketStore

func NewListPacketStore() packetStore

NewListPacketStore creates a new list-based packet store

Types

type AtomicTime

type AtomicTime struct {
	// contains filtered or unexported fields
}

AtomicTime provides atomic operations for time.Time values. Uses atomic.Value under the hood.

func (*AtomicTime) Load

func (at *AtomicTime) Load() time.Time

Load atomically loads the time.Time value. Returns zero time if not yet stored.

func (*AtomicTime) Store

func (at *AtomicTime) Store(t time.Time)

Store atomically stores the time.Time value.

type Config

type Config struct {
	InitialSequenceNumber  circular.Number
	PeriodicACKInterval    uint64 // microseconds
	PeriodicNAKInterval    uint64 // microseconds
	OnSendACK              func(seq circular.Number, light bool)
	OnSendNAK              func(list []circular.Number)
	OnDeliver              func(p packet.Packet)
	PacketReorderAlgorithm string                     // "list" (default) or "btree"
	BTreeDegree            int                        // B-tree degree (default: 32, only used if PacketReorderAlgorithm == "btree")
	LockTimingMetrics      *metrics.LockTimingMetrics // Optional lock timing metrics for performance monitoring
	ConnectionMetrics      *metrics.ConnectionMetrics // For atomic statistics updates

	// Buffer pool for zero-copy support (Phase 2: Lockless Design)
	// When provided, receiver.releasePacketFully() returns buffers to this pool
	BufferPool *sync.Pool

	// NAK btree configuration (Phase 4)
	UseNakBtree            bool    // Enable NAK btree for improved out-of-order handling
	SuppressImmediateNak   bool    // Suppress immediate NAK, let periodic NAK handle gaps
	TsbpdDelay             uint64  // Microseconds, for scan window calculation
	NakRecentPercent       float64 // Percentage of TSBPD delay for "recent" window (e.g., 0.10)
	NakMergeGap            uint32  // Maximum gap to merge into a single range
	NakConsolidationBudget uint64  // Microseconds, time budget for consolidation

	// FastNAK configuration
	FastNakEnabled       bool   // Enable FastNAK after silence
	FastNakThresholdUs   uint64 // Microseconds, silence threshold to trigger FastNAK
	FastNakRecentEnabled bool   // Enable FastNAKRecent to detect sequence jumps

	// NAK btree expiry configuration (nak_btree_expiry_optimization.md)
	NakExpiryMargin     float64 // Margin for expiry: threshold = now + RTO*(1+margin), default 0.10
	EWMAWarmupThreshold uint32  // Min samples before EWMA trusted (0=disabled), default 32

	// Light ACK configuration (Phase 5: ACK Optimization)
	LightACKDifference uint32 // Send Light ACK after N packets progress (default: 64)

	// Lock-free ring buffer configuration (Phase 3: Lockless Design)
	// When enabled, Push() writes to ring (lock-free), Tick() drains ring before processing
	UsePacketRing             bool          // Enable lock-free ring for packet handoff
	PacketRingSize            int           // Ring capacity per shard (must be power of 2)
	PacketRingShards          int           // Number of shards (must be power of 2)
	PacketRingMaxRetries      int           // Max immediate retries before backoff
	PacketRingBackoffDuration time.Duration // Delay between backoff retries
	PacketRingMaxBackoffs     int           // Max backoff iterations (0 = unlimited)
	PacketRingRetryStrategy   string        // Retry strategy: "", "sleep", "next", "random", "adaptive", "spin", "hybrid"

	// Event loop configuration (Phase 4: Lockless Design)
	// When enabled, replaces timer-driven Tick() with continuous event loop
	// REQUIRES: UsePacketRing=true (event loop consumes from ring)
	UseEventLoop          bool          // Enable continuous event loop
	EventLoopRateInterval time.Duration // Rate metric calculation interval (default: 1s)
	BackoffColdStartPkts  int           // Packets before adaptive backoff engages
	BackoffMinSleep       time.Duration // Minimum sleep during idle periods
	BackoffMaxSleep       time.Duration // Maximum sleep during idle periods

	// Time base configuration (Phase 10: EventLoop Time Fix)
	// When set, nowFn returns time relative to connection start, matching PktTsbpdTime.
	// This is REQUIRED for EventLoop mode to correctly handle TSBPD delivery.
	//
	// Without these fields: nowFn returns absolute Unix time (~1.7 trillion µs)
	// With these fields: nowFn returns TsbpdTimeBase + elapsed_since_StartTime
	//
	// PktTsbpdTime is calculated as: tsbpdTimeBase + timestamp + tsbpdDelay
	// For correct TSBPD comparison, nowFn must use the same time base.
	TsbpdTimeBase uint64    // Time base from connection (same as c.tsbpdTimeBase)
	StartTime     time.Time // Connection start time (same as c.start)

	// Debug logging (for investigation)
	// LogFunc is called for debug logging following the gosrt pattern:
	//   LogFunc("receiver:nak:debug", func() string { return "message" })
	Debug   bool                        // Enable debug logging
	LogFunc func(string, func() string) // Logging callback (lazy evaluation)

	// ProcessConnectionControlPackets is called by EventLoop to process
	// connection-level control packets (ACKACK, KEEPALIVE).
	// Returns number of packets processed.
	// Set by connection.go to c.drainRecvControlRing.
	// This allows control packets to be processed inline in EventLoop
	// rather than by a separate polling goroutine, eliminating latency.
	ProcessConnectionControlPackets func() int
}

Config is the configuration for the liveRecv congestion control

type NAKEntry

type NAKEntry struct {
	Start uint32
	End   uint32 // Same as Start for singles
}

NAKEntry represents either a single sequence or a range.

func (NAKEntry) Count

func (e NAKEntry) Count() uint32

Count returns the number of sequences covered by this entry.

func (NAKEntry) IsRange

func (e NAKEntry) IsRange() bool

IsRange returns true if this entry represents a range (more than one sequence).

type NakEntryWithTime

type NakEntryWithTime struct {
	Seq           uint32 // Missing sequence number
	TsbpdTimeUs   uint64 // TSBPD release time for this sequence (microseconds) - for expiry
	LastNakedAtUs uint64 // When we last sent NAK for this seq (microseconds) - for suppression
	NakCount      uint32 // Number of times NAK'd
}

NakEntryWithTime stores a missing sequence number with timing information. Used in NAK btree to track: - When the packet should be delivered (TsbpdTimeUs) - for RTT-aware expiry - When we last sent NAK (LastNakedAtUs) - for NAK suppression - How many times NAK'd (NakCount) - for metrics

Phase 6: RTO Suppression - prevents redundant NAKs within RTO window. Phase 7: NAK Btree Expiry Optimization - RTT-aware early expiry (nak_btree_expiry_optimization.md)

type RecvControlPacket

type RecvControlPacket struct {
	// Type identifies the control packet type
	Type RecvControlPacketType

	// ACKNumber is the ACK number being acknowledged (for ACKACK only)
	ACKNumber uint32

	// Timestamp is the arrival time in nanoseconds (time.Now().UnixNano())
	// Captured at push time to ensure accurate RTT calculation
	Timestamp int64
}

RecvControlPacket wraps an ACKACK or KEEPALIVE for ring transport. This is a value type (not pointer) to avoid allocations in the hot path.

func (RecvControlPacket) ArrivalTime

func (p RecvControlPacket) ArrivalTime() time.Time

ArrivalTime returns the Timestamp as a time.Time

type RecvControlPacketType

type RecvControlPacketType uint8

RecvControlPacketType identifies the type of receiver control packet

const (
	// RecvControlTypeACKACK is an ACKACK packet for RTT calculation
	RecvControlTypeACKACK RecvControlPacketType = iota

	// RecvControlTypeKEEPALIVE is a KEEPALIVE packet for connection maintenance
	RecvControlTypeKEEPALIVE
)

func (RecvControlPacketType) String

func (t RecvControlPacketType) String() string

String returns the string representation of the control packet type

type RecvControlRing

type RecvControlRing struct {
	*common.ControlRing[RecvControlPacket]
}

RecvControlRing wraps the generic control ring for receiver control packets. Push*() is called from io_uring completion handlers (multiple goroutines). TryPop() is called from EventLoop (single consumer).

func NewRecvControlRing

func NewRecvControlRing(size, shards int) (*RecvControlRing, error)

NewRecvControlRing creates a receiver control ring.

Parameters:

  • size: per-shard capacity (default: 128)
  • shards: number of shards (default: 1)

Reference: completely_lockfree_receiver.md Section 6.1.3

func (*RecvControlRing) PushACKACK

func (r *RecvControlRing) PushACKACK(ackNum uint32, arrivalTime time.Time) bool

PushACKACK pushes an ACKACK to the control ring. Thread-safe: can be called from multiple goroutines (io_uring handlers). Returns true if successful, false if ring is full.

The arrivalTime is captured at push time to ensure accurate RTT calculation. This is critical because the EventLoop may process the packet later, and using time.Now() at processing time would include queueing delay.

func (*RecvControlRing) PushKEEPALIVE

func (r *RecvControlRing) PushKEEPALIVE() bool

PushKEEPALIVE pushes a KEEPALIVE to the control ring. Thread-safe: can be called from multiple goroutines (io_uring handlers). Returns true if successful, false if ring is full.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址