Documentation
¶
Overview ¶
Package metrics provides high-performance atomic counters and Prometheus metrics for SRT connection statistics and monitoring.
Index ¶
- Constants
- func CountNAKEntries(m *ConnectionMetrics, list []circular.Number, counterType NAKCounterType) uint64
- func GetConnections() map[uint32]*ConnectionInfo
- func GetProgramStartTime() time.Time
- func IncrementRecvDataDrop(m *ConnectionMetrics, reason DropReason, pktLen uint64)
- func IncrementRecvErrorDrop(m *ConnectionMetrics, p packet.Packet, reason DropReason, isData bool)
- func IncrementRecvErrorMetrics(m *ConnectionMetrics, isIoUring bool, errorType DropReason)
- func IncrementRecvMetrics(m *ConnectionMetrics, p packet.Packet, isIoUring bool, success bool, ...)
- func IncrementSendControlMetric(m *ConnectionMetrics, controlType packet.CtrlType)
- func IncrementSendDataDrop(m *ConnectionMetrics, reason DropReason, pktLen uint64)
- func IncrementSendErrorDrop(m *ConnectionMetrics, p packet.Packet, reason DropReason, pktLen uint64)
- func IncrementSendErrorMetrics(m *ConnectionMetrics, isIoUring bool, errorType DropReason)
- func IncrementSendMetrics(m *ConnectionMetrics, p packet.Packet, isIoUring bool, success bool, ...)
- func MetricsHandler() http.Handler
- func RegisterConnection(socketId uint32, info *ConnectionInfo)
- func StabilizationHandler() http.Handler
- func UnregisterConnection(socketId uint32, reason CloseReason)
- func WithLockTiming(metrics *LockTimingMetrics, mutex interface{ ... }, fn func())
- func WithRLockTiming(metrics *LockTimingMetrics, mutex interface{ ... }, fn func())
- func WithWLockTiming(metrics *LockTimingMetrics, mutex interface{ ... }, fn func())
- type CloseReason
- type ConnectionInfo
- type ConnectionMetrics
- func (m *ConnectionMetrics) GetRecvRateBytesPerSec() float64
- func (m *ConnectionMetrics) GetRecvRateMbps() float64
- func (m *ConnectionMetrics) GetRecvRatePacketsPerSec() float64
- func (m *ConnectionMetrics) GetRecvRateRetransPercent() float64
- func (m *ConnectionMetrics) GetSendRateEstInputBW() float64
- func (m *ConnectionMetrics) GetSendRateEstSentBW() float64
- func (m *ConnectionMetrics) GetSendRateMbps() float64
- func (m *ConnectionMetrics) GetSendRateRetransPercent() float64
- type DropReason
- type IoUringRingMetrics
- type ListenerMetrics
- type LockTimingMetrics
- func (ltm *LockTimingMetrics) GetStats() (holdAvg, holdMax, waitAvg, waitMax float64)
- func (ltm *LockTimingMetrics) GetTotalAcquisitions() uint64
- func (ltm *LockTimingMetrics) RecordHoldTime(duration time.Duration)
- func (ltm *LockTimingMetrics) RecordWaitTime(duration time.Duration)
- func (ltm *LockTimingMetrics) SnapshotHoldTimes() [LockTimingSamples]int64
- func (ltm *LockTimingMetrics) SnapshotWaitTimes() [LockTimingSamples]int64
- type MetricsGetter
- type MetricsRegistry
- type NAKCounterType
- type ProcStat
- type StabilizationConfig
- type StabilizationMetrics
- type StabilizationResult
Constants ¶
const (
// LockTimingSamples is the number of recent samples to keep for lock timing
LockTimingSamples = 10
)
Variables ¶
This section is empty.
Functions ¶
func CountNAKEntries ¶
func CountNAKEntries(m *ConnectionMetrics, list []circular.Number, counterType NAKCounterType) uint64
CountNAKEntries iterates through a NAK loss list and increments the appropriate single/range/total counters. This function is used by BOTH:
- Receiver when generating NAKs (NAKCounterSend)
- Sender when receiving NAKs (NAKCounterRecv)
Using the same function for both paths ensures counters are 100% consistent between endpoints, which is critical for NAK delivery rate calculations.
The loss list format is pairs of [start, end] circular.Number values:
- If start == end: Single packet NAK entry (1 packet)
- If start != end: Range NAK entry (end.Distance(start) + 1 packets)
RFC SRT Appendix A:
- Figure 21: Single packet entry (4 bytes on wire)
- Figure 22: Range entry (8 bytes on wire)
Returns the total number of packets requested by the NAK list.
func GetConnections ¶
func GetConnections() map[uint32]*ConnectionInfo
GetConnections returns a snapshot of all registered connections with their metadata. Returns: map of socketId -> ConnectionInfo (contains metrics + metadata) This is safe to call concurrently (uses RLock for concurrent reads).
func GetProgramStartTime ¶
GetProgramStartTime returns the time when the program started. Useful for testing and external uptime calculations.
func IncrementRecvDataDrop ¶
func IncrementRecvDataDrop(m *ConnectionMetrics, reason DropReason, pktLen uint64)
IncrementRecvDataDrop increments both granular and aggregate drop counters for receiver This ensures granular and aggregate counters stay in sync Metrics are guaranteed to be non-nil (initialized in connection.go before NewReceiver)
func IncrementRecvErrorDrop ¶
func IncrementRecvErrorDrop(m *ConnectionMetrics, p packet.Packet, reason DropReason, isData bool)
IncrementRecvErrorDrop increments granular error counters for receive path For DATA packets, also increments the aggregate PktRecvDataError counter Note: For receive path, we may not have a packet object when errors occur Metrics are guaranteed to be non-nil (initialized in connection.go before NewReceiver)
func IncrementRecvErrorMetrics ¶
func IncrementRecvErrorMetrics(m *ConnectionMetrics, isIoUring bool, errorType DropReason)
IncrementRecvErrorMetrics increments error metrics for cases where we don't have a packet Exported for use in receive paths
func IncrementRecvMetrics ¶
func IncrementRecvMetrics(m *ConnectionMetrics, p packet.Packet, isIoUring bool, success bool, dropReason DropReason)
IncrementRecvMetrics increments the appropriate receive metrics based on packet type and outcome This is a helper function to reduce code duplication in receive paths Exported for use in receive paths (listen_linux.go, dial_linux.go, etc.) dropReason should be DropReason(0) for success cases
func IncrementSendControlMetric ¶
func IncrementSendControlMetric(m *ConnectionMetrics, controlType packet.CtrlType)
IncrementSendControlMetric increments the appropriate send counter for a control packet type. This is used by the io_uring path where control packets are decommissioned before IncrementSendMetrics can classify them.
func IncrementSendDataDrop ¶
func IncrementSendDataDrop(m *ConnectionMetrics, reason DropReason, pktLen uint64)
IncrementSendDataDrop increments both granular and aggregate drop counters for sender This ensures granular and aggregate counters stay in sync Metrics are guaranteed to be non-nil (initialized in connection.go before NewSender)
func IncrementSendErrorDrop ¶
func IncrementSendErrorDrop(m *ConnectionMetrics, p packet.Packet, reason DropReason, pktLen uint64)
IncrementSendErrorDrop increments granular error counters and aggregate for DATA packets For control packets, only increments granular counter (not included in aggregate) Metrics are guaranteed to be non-nil (initialized in connection.go before NewSender)
func IncrementSendErrorMetrics ¶
func IncrementSendErrorMetrics(m *ConnectionMetrics, isIoUring bool, errorType DropReason)
IncrementSendErrorMetrics increments error metrics for cases where we don't have a packet Exported for use in send paths
func IncrementSendMetrics ¶
func IncrementSendMetrics(m *ConnectionMetrics, p packet.Packet, isIoUring bool, success bool, dropReason DropReason)
IncrementSendMetrics increments the appropriate send metrics based on packet type and outcome This is a helper function to reduce code duplication in send paths Exported for use in send paths (connection_linux.go, connection.go, etc.) dropReason should be DropReason(0) for success cases
func MetricsHandler ¶
MetricsHandler returns an HTTP handler that serves Prometheus-formatted metrics Performance is optimized by using a sync.Pool for strings.Builder and a scratch buffer for number formatting. Remember - when adding metrics, also update handler_test.go Remember to also run "make audit-metrics" to verify all metrics are defined, used, and exported to Prometheus
func RegisterConnection ¶
func RegisterConnection(socketId uint32, info *ConnectionInfo)
RegisterConnection registers a connection's metrics with metadata. The ConnectionInfo contains all information needed for Prometheus labeling.
func StabilizationHandler ¶
StabilizationHandler returns an HTTP handler for the /stabilize endpoint. The output format is simple key=value lines, one per metric:
data_sent=12345 data_recv=12340 ack_sent=500 ack_recv=498 nak_sent=5 nak_recv=3
This is optimized for fast generation (6 atomic loads) and fast parsing. Reuses metricsBuilderPool from handler.go to minimize memory overhead.
func UnregisterConnection ¶
func UnregisterConnection(socketId uint32, reason CloseReason)
UnregisterConnection removes a connection's metrics and increments the appropriate close counter based on the reason.
func WithLockTiming ¶
func WithLockTiming(metrics *LockTimingMetrics, mutex interface { Lock() Unlock() }, fn func())
WithLockTiming executes a function while measuring lock hold and wait times for a regular Mutex
func WithRLockTiming ¶
func WithRLockTiming(metrics *LockTimingMetrics, mutex interface { RLock() RUnlock() }, fn func())
WithRLockTiming executes a function while measuring read lock hold and wait times for an RWMutex
func WithWLockTiming ¶
func WithWLockTiming(metrics *LockTimingMetrics, mutex interface { Lock() Unlock() }, fn func())
WithWLockTiming executes a function while measuring write lock hold and wait times for an RWMutex
Types ¶
type CloseReason ¶
type CloseReason int
CloseReason indicates why a connection was closed. Used for tracking connection lifecycle in metrics.
const ( CloseReasonGraceful CloseReason = iota // Normal shutdown (Close() called) CloseReasonPeerIdle // Peer idle timeout expired CloseReasonContextCancel // Parent context canceled CloseReasonError // Error during operation )
type ConnectionInfo ¶
type ConnectionInfo struct {
Metrics *ConnectionMetrics
InstanceName string // Instance name for Prometheus labeling (e.g., "baseline-server")
RemoteAddr string // Remote IP:port (e.g., "10.1.1.2:45678")
StreamId string // Stream ID (e.g., "publish:/test-stream")
PeerType string // "publisher", "subscriber", or "unknown"
PeerSocketID uint32 // Remote peer's socket ID (for cross-process connection correlation)
StartTime time.Time // When connection was established (for age metrics)
}
ConnectionInfo holds metadata for a registered connection. This enables richer Prometheus labels for connection identification.
type ConnectionMetrics ¶
type ConnectionMetrics struct {
// Single counter for all successful receives (for peer idle timeout)
PktRecvSuccess atomic.Uint64
// Edge case tracking (should never increment, but defensive programming)
PktRecvNil atomic.Uint64 // Nil packet edge case
PktRecvControlUnknown atomic.Uint64 // Unknown control packet types
PktRecvSubTypeUnknown atomic.Uint64 // Unknown USER packet subtypes
// Packet counters (atomic for performance)
PktRecvDataSuccess atomic.Uint64
PktRecvDataDropped atomic.Uint64
PktRecvDataError atomic.Uint64
PktSentDataSuccess atomic.Uint64
// PktSentDataDropped atomic.Uint64 // Not implemented - send drops tracked via CongestionSendPktDrop
PktSentDataError atomic.Uint64
// Control packet counters - ACK
PktRecvACKSuccess atomic.Uint64
// PktRecvACKDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvACKError atomic.Uint64 // Not implemented - control packets currently never error
PktSentACKSuccess atomic.Uint64
// Control packet counters - ACK (Light vs Full breakdown) - Phase 5: ACK Optimization
PktSentACKLiteSuccess atomic.Uint64 // Light ACKs sent (sequence only, no RTT)
PktSentACKFullSuccess atomic.Uint64 // Full ACKs sent (includes RTT, triggers ACKACK)
PktRecvACKLiteSuccess atomic.Uint64 // Light ACKs received
PktRecvACKFullSuccess atomic.Uint64 // Full ACKs received
// Control packet counters - ACKACK
PktRecvACKACKSuccess atomic.Uint64
// PktRecvACKACKDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvACKACKError atomic.Uint64 // Not implemented - control packets currently never error
PktSentACKACKSuccess atomic.Uint64
// Control packet counters - NAK
PktRecvNAKSuccess atomic.Uint64
// PktRecvNAKDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvNAKError atomic.Uint64 // Not implemented - control packets currently never error
PktSentNAKSuccess atomic.Uint64
// Control packet counters - KM
PktRecvKMSuccess atomic.Uint64
// PktRecvKMDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvKMError atomic.Uint64 // Not implemented - control packets currently never error
PktSentKMSuccess atomic.Uint64
// Control packet counters - Keepalive
PktRecvKeepaliveSuccess atomic.Uint64
// PktRecvKeepaliveDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvKeepaliveError atomic.Uint64 // Not implemented - control packets currently never error
PktSentKeepaliveSuccess atomic.Uint64
// Control packet counters - Shutdown
PktRecvShutdownSuccess atomic.Uint64
// PktRecvShutdownDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvShutdownError atomic.Uint64 // Not implemented - control packets currently never error
PktSentShutdownSuccess atomic.Uint64
// Control packet counters - Handshake
PktRecvHandshakeSuccess atomic.Uint64
// PktRecvHandshakeDropped atomic.Uint64 // Not implemented - control packets currently never dropped
// PktRecvHandshakeError atomic.Uint64 // Not implemented - control packets currently never error
PktSentHandshakeSuccess atomic.Uint64
// Path-specific counters
PktRecvIoUring atomic.Uint64
PktRecvReadFrom atomic.Uint64
PktSentIoUring atomic.Uint64
PktSentWriteTo atomic.Uint64
PktSentSubmitted atomic.Uint64 // io_uring submissions (for detecting lost completions)
// Error counters (detailed)
PktRecvErrorIoUring atomic.Uint64
PktRecvErrorParse atomic.Uint64
PktRecvErrorRoute atomic.Uint64
PktRecvErrorEmpty atomic.Uint64
PktRecvErrorUnknown atomic.Uint64 // Unknown/unexpected error (unrecognized drop reason)
PktSentErrorIoUring atomic.Uint64
PktSentErrorMarshal atomic.Uint64
PktSentErrorSubmit atomic.Uint64
PktSentErrorUnknown atomic.Uint64 // Unknown/unexpected error (unrecognized drop reason)
// Crypto operation error counters
CryptoErrorEncrypt atomic.Uint64 // Encryption/decryption payload errors
CryptoErrorGenerateSEK atomic.Uint64 // SEK generation errors
CryptoErrorMarshalKM atomic.Uint64 // Key material marshaling errors
// Routing failure counters
PktRecvUnknownSocketId atomic.Uint64
PktRecvNilConnection atomic.Uint64
PktRecvWrongPeer atomic.Uint64
PktRecvBacklogFull atomic.Uint64
// Resource exhaustion counters
PktSentRingFull atomic.Uint64
PktRecvQueueFull atomic.Uint64
// Lock timing (see Lock Timing Metrics section)
HandlePacketLockTiming *LockTimingMetrics
ReceiverLockTiming *LockTimingMetrics
SenderLockTiming *LockTimingMetrics
// Byte counters (for completeness)
ByteRecvDataSuccess atomic.Uint64
ByteRecvDataDropped atomic.Uint64
ByteSentDataSuccess atomic.Uint64
// Special counters (from connStats migration)
PktRecvUndecrypt atomic.Uint64
ByteRecvUndecrypt atomic.Uint64
PktRecvInvalid atomic.Uint64
PktRetransFromNAK atomic.Uint64
HeaderSize atomic.Uint64
MbpsLinkCapacity atomic.Uint64 // Stored as uint64 (Mbps * 1000)
// Congestion control - Receiver statistics
CongestionRecvPkt atomic.Uint64
CongestionRecvByte atomic.Uint64
CongestionRecvPktUnique atomic.Uint64
CongestionRecvByteUnique atomic.Uint64
CongestionRecvPktLoss atomic.Uint64
CongestionRecvByteLoss atomic.Uint64
CongestionRecvPktRetrans atomic.Uint64
CongestionRecvByteRetrans atomic.Uint64
CongestionRecvPktBelated atomic.Uint64
CongestionRecvByteBelated atomic.Uint64
CongestionRecvPktDrop atomic.Uint64
CongestionRecvByteDrop atomic.Uint64
CongestionRecvPktBuf atomic.Uint64
CongestionRecvByteBuf atomic.Uint64
CongestionRecvMsBuf atomic.Uint64
CongestionRecvBytePayload atomic.Uint64
CongestionRecvMbpsBandwidth atomic.Uint64 // Mbps * 1000
CongestionRecvMbpsLinkCapacity atomic.Uint64 // Mbps * 1000
CongestionRecvPktRetransRate atomic.Uint64 // Retransmission rate: bytesRetrans/bytesRecv * 100 (NOT loss rate)
// Duplicate packet tracking (defensive check in btree Insert)
// Primary duplicate detection is in push.go; this catches edge cases
CongestionRecvPktDuplicate atomic.Uint64 // Duplicate data packets detected by btree
CongestionRecvByteDuplicate atomic.Uint64 // Duplicate data bytes
// NAK generation counters - Receiver sends NAKs to request retransmission
// RFC SRT Appendix A defines two NAK encoding formats:
// - Single packet (Figure 21): 4 bytes, bit 0 = 0
// - Range of packets (Figure 22): 8 bytes, bit 0 of first = 1
// These counters track PACKETS requested, not entries:
// NAKSingle + NAKRange = NAKPktsTotal = expected retransmissions
CongestionRecvNAKSingle atomic.Uint64 // Packets requested via single NAK entries (1 per entry)
CongestionRecvNAKRange atomic.Uint64 // Packets requested via range NAK entries (sum of range sizes)
CongestionRecvNAKPktsTotal atomic.Uint64 // Total packets requested = NAKSingle + NAKRange
// Congestion control - Sender statistics
CongestionSendPkt atomic.Uint64
CongestionSendByte atomic.Uint64
CongestionSendPktUnique atomic.Uint64
CongestionSendByteUnique atomic.Uint64
CongestionSendPktLoss atomic.Uint64
CongestionSendByteLoss atomic.Uint64
CongestionSendPktRetrans atomic.Uint64
CongestionSendByteRetrans atomic.Uint64
CongestionSendUsSndDuration atomic.Uint64
CongestionSendPktDrop atomic.Uint64
CongestionSendByteDrop atomic.Uint64
CongestionSendPktBuf atomic.Uint64
CongestionSendByteBuf atomic.Uint64
CongestionSendMsBuf atomic.Uint64
CongestionSendPktFlightSize atomic.Uint64
CongestionSendUsPktSndPeriod atomic.Uint64
CongestionSendBytePayload atomic.Uint64
CongestionSendMbpsInputBandwidth atomic.Uint64 // Mbps * 1000
CongestionSendMbpsSentBandwidth atomic.Uint64 // Mbps * 1000
CongestionSendPktRetransRate atomic.Uint64 // Retransmission rate: bytesRetrans/bytesSent * 100 (NOT loss rate)
// Additional error/drop counters for congestion control
CongestionRecvPktNil atomic.Uint64 // Nil packets received
CongestionRecvPktStoreInsertFailed atomic.Uint64 // Packet store insertion failures
// Defensive counters for "should never happen" conditions (ISSUE-001)
// These track programming errors or invalid state - should always be 0
NakBtreeNilWhenEnabled atomic.Uint64 // nakBtree nil when useNakBtree=true
CongestionSendNAKNotFound atomic.Uint64 // NAK requests for packets not in lossList
NakBeforeACKCount atomic.Uint64 // NAK requests for already-ACK'd sequences (receiver bug indicator)
// NAK receive counters - Sender receives NAKs and retransmits
// RFC SRT Appendix A defines two NAK encoding formats:
// - Single packet (Figure 21): 4 bytes, bit 0 = 0
// - Range of packets (Figure 22): 8 bytes, bit 0 of first = 1
// These counters track PACKETS requested, not entries:
// NAKSingleRecv + NAKRangeRecv = NAKPktsRecv = expected retransmissions
CongestionSendNAKSingleRecv atomic.Uint64 // Packets requested via single NAK entries (1 per entry)
CongestionSendNAKRangeRecv atomic.Uint64 // Packets requested via range NAK entries (sum of range sizes)
CongestionSendNAKPktsRecv atomic.Uint64 // Total packets requested = NAKSingleRecv + NAKRangeRecv
CongestionSendNAKHonoredOrder atomic.Uint64 // NAK processing runs that honored receiver priority order
// Granular drop counters - Congestion control (DATA packets only)
CongestionRecvDataDropTooOld atomic.Uint64 // Belated, past play time
CongestionRecvDataDropAlreadyAcked atomic.Uint64 // Already acknowledged
CongestionRecvDataDropDuplicate atomic.Uint64 // Duplicate (already in store)
CongestionRecvDataDropStoreInsertFailed atomic.Uint64 // Store insert failed
CongestionSendDataDropTooOld atomic.Uint64 // Exceed drop threshold
// TSBPD skip counters - Packets that NEVER arrived and were skipped when ACK advanced
// These are distinct from "drops" which track packets that ARRIVED but were discarded
CongestionRecvPktSkippedTSBPD atomic.Uint64 // Packets skipped at TSBPD time (never arrived)
CongestionRecvByteSkippedTSBPD atomic.Uint64 // Bytes skipped (estimated from avgPayloadSize)
ContiguousPointTSBPDAdvancements atomic.Uint64 // Count of times contiguousPoint advanced due to TSBPD expiry
ContiguousPointTSBPDSkippedPktsTotal atomic.Uint64 // Total packets skipped across all TSBPD advancements
// Periodic timer tick counters - Track that timer routines are running
// Used for health monitoring: should grow linearly with test duration
// Expected: ACK ~100/sec (10ms interval), NAK ~50/sec (20ms interval)
CongestionRecvPeriodicACKRuns atomic.Uint64 // Times periodicACK() actually ran
CongestionRecvPeriodicNAKRuns atomic.Uint64 // Times periodicNAK() actually ran
// NAK btree metrics - Core operations
NakBtreeInserts atomic.Uint64 // Sequences added to NAK btree
NakBtreeDeletes atomic.Uint64 // Sequences removed (packet arrived)
NakBtreeExpired atomic.Uint64 // Sequences removed (sequence-based expiry, fallback)
NakBtreeExpiredEarly atomic.Uint64 // Sequences removed RTT before TSBPD (time-based)
NakBtreeSkippedExpired atomic.Uint64 // Sequences not inserted (already expired at gap detection)
NakBtreeSize atomic.Uint64 // Current size (gauge, updated each periodic NAK)
// NAK TSBPD estimation metrics (nak_btree_expiry_optimization.md)
NakTsbpdEstBoundary atomic.Uint64 // TSBPD estimated using boundary packets (linear interpolation)
NakTsbpdEstEWMA atomic.Uint64 // TSBPD estimated using inter-packet EWMA (warm fallback)
NakTsbpdEstColdFallback atomic.Uint64 // TSBPD estimated during EWMA warm-up (conservative)
NakBtreeScanPackets atomic.Uint64 // Packets scanned in periodicNakBtree()
NakBtreeScanGaps atomic.Uint64 // Gaps found during scan
// NAK btree metrics - Periodic NAK execution
NakPeriodicOriginalRuns atomic.Uint64 // Times periodicNakOriginal() executed
NakPeriodicBtreeRuns atomic.Uint64 // Times periodicNakBtree() executed
NakPeriodicSkipped atomic.Uint64 // Times skipped (interval not elapsed)
// NAK btree metrics - Consolidation
NakConsolidationRuns atomic.Uint64 // Times consolidateNakBtree() ran
NakConsolidationEntries atomic.Uint64 // Total entries produced by consolidation
NakConsolidationMerged atomic.Uint64 // Times adjacent sequences merged into ranges
NakConsolidationTimeout atomic.Uint64 // Times consolidation hit time budget
// Suppression metrics (future implementation - RTO-based)
// These are placeholders for retransmission_and_nak_suppression_design.md
NakSuppressedSeqs atomic.Uint64 // NAK entries skipped (already NAK'd recently, awaiting RTO)
NakAllowedSeqs atomic.Uint64 // NAK entries that passed RTO threshold
RetransSuppressed atomic.Uint64 // Sender retransmissions skipped (already in flight)
RetransAllowed atomic.Uint64 // Sender retransmissions that passed RTO threshold
RetransFirstTime atomic.Uint64 // NAK retransmits where TransmitCount was 0 (edge case - packet never first-sent)
// NAK btree metrics - FastNAK
NakFastTriggers atomic.Uint64 // Times FastNAK triggered after silence
NakFastRecentInserts atomic.Uint64 // Sequences added by FastNAKRecent jump detection
NakFastRecentSkipped atomic.Uint64 // FastNAKRecent skipped (gap too small)
NakFastRecentOverflow atomic.Uint64 // FastNAKRecent gap too large (capped)
// NAK packet splitting metrics (FR-11: MSS overflow handling)
NakPacketsSplit atomic.Uint64 // Extra NAK packets needed due to MSS overflow
// Granular error counters - Connection-level receive (DATA and Control packets)
PktRecvDataErrorParse atomic.Uint64 // DATA packet parse errors
PktRecvControlErrorParse atomic.Uint64 // Control packet parse errors
PktRecvDataErrorIoUring atomic.Uint64 // DATA packet io_uring errors
PktRecvControlErrorIoUring atomic.Uint64 // Control packet io_uring errors
PktRecvDataErrorEmpty atomic.Uint64 // DATA packet empty datagrams
PktRecvControlErrorEmpty atomic.Uint64 // Control packet empty datagrams
PktRecvDataErrorRoute atomic.Uint64 // DATA packet routing failures
PktRecvControlErrorRoute atomic.Uint64 // Control packet routing failures
// Granular error counters - Connection-level send (DATA and Control packets)
PktSentDataErrorMarshal atomic.Uint64 // DATA packet marshal errors
PktSentControlErrorMarshal atomic.Uint64 // Control packet marshal errors
PktSentDataRingFull atomic.Uint64 // DATA packet ring full
PktSentControlRingFull atomic.Uint64 // Control packet ring full
PktSentDataErrorSubmit atomic.Uint64 // DATA packet submit errors
PktSentControlErrorSubmit atomic.Uint64 // Control packet submit errors
PktSentDataErrorIoUring atomic.Uint64 // DATA packet io_uring completion errors
PktSentControlErrorIoUring atomic.Uint64 // Control packet io_uring completion errors
RingDropsTotal atomic.Uint64 // Packets dropped due to ring full (after backoff)
RingDrainedPackets atomic.Uint64 // Packets successfully drained from ring to btree
RingPacketsProcessed atomic.Uint64 // Total packets consumed from ring (for delta calculation)
SendTickRuns atomic.Uint64 // Number of Tick() invocations
SendTickDeliveredPackets atomic.Uint64 // Packets delivered during Tick() calls
SendRingPushed atomic.Uint64 // Packets successfully pushed to sender ring
SendRingDropped atomic.Uint64 // Packets dropped due to sender ring full
SendSeqAssigned atomic.Uint64 // Sequence numbers assigned (atomic 31-bit)
SendSeqWraparound atomic.Uint64 // Times sequence wrapped past MAX_SEQUENCENUMBER
SendFirstTransmit atomic.Uint64 // Packets sent with TransmitCount 0→1 (first send)
SendAlreadySent atomic.Uint64 // Packets skipped in delivery (TransmitCount>=1)
SendRingDrained atomic.Uint64 // Packets drained from sender ring to btree
SendBtreeInserted atomic.Uint64 // Packets inserted into sender btree
SendBtreeDuplicates atomic.Uint64 // Duplicate packets detected in sender btree
SendRingDrainSeqGap atomic.Uint64 // Sequence gaps detected during ring→btree drain (sender bug indicator)
SendControlRingPushedACK atomic.Uint64 // ACKs successfully pushed to control ring
SendControlRingPushedNAK atomic.Uint64 // NAKs successfully pushed to control ring
SendControlRingDroppedACK atomic.Uint64 // ACKs dropped due to control ring full
SendControlRingDroppedNAK atomic.Uint64 // NAKs dropped due to control ring full
SendControlRingDrained atomic.Uint64 // Control packets drained by EventLoop
SendControlRingProcessed atomic.Uint64 // Control packets processed by EventLoop (total)
SendControlRingProcessedACK atomic.Uint64 // ACKs processed by EventLoop
SendControlRingProcessedNAK atomic.Uint64 // NAKs processed by EventLoop
RecvControlRingPushedACKACK atomic.Uint64 // ACKACKs successfully pushed to control ring
RecvControlRingPushedKEEPALIVE atomic.Uint64 // KEEPALIVEs successfully pushed to control ring
RecvControlRingDroppedACKACK atomic.Uint64 // ACKACKs dropped due to control ring full (fallback to locked path)
RecvControlRingDroppedKEEPALIVE atomic.Uint64 // KEEPALIVEs dropped due to control ring full (fallback to locked path)
RecvControlRingDrained atomic.Uint64 // Control packets drained by EventLoop
RecvControlRingProcessed atomic.Uint64 // Control packets processed by EventLoop (total)
RecvControlRingProcessedACKACK atomic.Uint64 // ACKACKs processed by EventLoop
RecvControlRingProcessedKEEPALIVE atomic.Uint64 // KEEPALIVEs processed by EventLoop
// Startup diagnostics (debug intermittent failures)
SendEventLoopStartAttempts atomic.Uint64 // Times EventLoop() was called
SendEventLoopSkippedDisabled atomic.Uint64 // Times EventLoop returned early (useEventLoop=false)
SendEventLoopStarted atomic.Uint64 // Times EventLoop entered main loop
SendEventLoopIterations atomic.Uint64 // Total EventLoop iterations
SendEventLoopDefaultRuns atomic.Uint64 // Default case runs (no timer fired)
SendEventLoopDropFires atomic.Uint64 // Drop ticker fires
SendEventLoopDataDrained atomic.Uint64 // Data packets drained from ring
SendEventLoopControlDrained atomic.Uint64 // Control packets drained from ring
SendEventLoopACKsProcessed atomic.Uint64 // ACKs processed by EventLoop
SendEventLoopNAKsProcessed atomic.Uint64 // NAKs processed by EventLoop
SendEventLoopIdleBackoffs atomic.Uint64 // Times EventLoop entered idle backoff
SendEventLoopTightCapReached atomic.Uint64 // Times MaxDataPerIteration cap was hit (tight loop mode)
// Diagnostic metrics for drain debugging
SendEventLoopDrainAttempts atomic.Uint64 // Times drain was called
SendEventLoopDrainRingNil atomic.Uint64 // Times packetRing was nil
SendEventLoopDrainRingEmpty atomic.Uint64 // Times TryPop returned empty (first try)
SendEventLoopDrainRingHadData atomic.Uint64 // Times ring.Len() > 0 before drain
SendEventLoopTsbpdSleeps atomic.Uint64 // Times EventLoop used TSBPD-aware sleep
SendEventLoopEmptyBtreeSleeps atomic.Uint64 // Times EventLoop slept due to empty btree
SendEventLoopSleepClampedMin atomic.Uint64 // Times sleep was clamped to minimum
SendEventLoopSleepClampedMax atomic.Uint64 // Times sleep was clamped to maximum
SendEventLoopSleepTotalUs atomic.Uint64 // Total sleep time in microseconds
SendEventLoopNextDeliveryTotalUs atomic.Uint64 // Total next delivery time in microseconds
SendDeliveryPackets atomic.Uint64 // Packets delivered by EventLoop
SendBtreeLen atomic.Uint64 // Current btree length (updated per iteration)
// Delivery debugging metrics
SendDeliveryAttempts atomic.Uint64 // Times deliverReadyPacketsEventLoop was called
SendDeliveryBtreeEmpty atomic.Uint64 // Times btree was empty when trying to deliver
SendDeliveryIterStarted atomic.Uint64 // Times IterateFrom called callback (had packets)
SendDeliveryTsbpdNotReady atomic.Uint64 // Times first packet had tsbpdTime > nowUs
SendDeliveryLastNowUs atomic.Uint64 // Last nowUs value (for debugging)
SendDeliveryLastTsbpd atomic.Uint64 // Last first packet's tsbpdTime (for debugging)
SendDeliveryStartSeq atomic.Uint64 // Last deliveryStartPoint value (for debugging)
SendDeliveryBtreeMinSeq atomic.Uint64 // Btree min sequence (for debugging IterateFrom)
SendDropAheadOfDelivery atomic.Uint64 // Packets dropped that were ahead of deliveryStartPoint (head-of-line blocking)
// ========================================================================
// Zero-Copy Payload Pool Metrics (Phase 5: Lockless Sender)
// ========================================================================
// Tracks payload validation and buffer pool usage.
SendPayloadSizeErrors atomic.Uint64 // Payloads rejected due to size validation
// Receiver rate counters - accumulate between rate calculations
RecvRatePeriodUs atomic.Uint64 // Rate calculation period (microseconds), default 1s
RecvRateLastUs atomic.Uint64 // Last rate calculation time (microseconds since epoch)
RecvRatePackets atomic.Uint64 // Packets received in current period
RecvRateBytes atomic.Uint64 // Bytes received in current period
RecvRateBytesRetrans atomic.Uint64 // Retransmitted bytes in current period
// Receiver computed rates - updated atomically during rate calculation
// Stored as uint64 using math.Float64bits(), read with math.Float64frombits()
RecvRatePacketsPerSec atomic.Uint64 // Packets per second (float64 bits)
RecvRateBytesPerSec atomic.Uint64 // Bytes per second (float64 bits)
RecvRatePktRetransRate atomic.Uint64 // Retransmission rate percentage (float64 bits)
// Sender rate counters - accumulate between rate calculations
SendRatePeriodUs atomic.Uint64 // Rate calculation period (microseconds), default 1s
SendRateLastUs atomic.Uint64 // Last rate calculation time (microseconds since epoch)
SendRateBytes atomic.Uint64 // Bytes input in current period
SendRateBytesSent atomic.Uint64 // Bytes actually sent in current period
SendRateBytesRetrans atomic.Uint64 // Retransmitted bytes in current period
// Sender computed rates - updated atomically during rate calculation
// Stored as uint64 using math.Float64bits(), read with math.Float64frombits()
SendRateEstInputBW atomic.Uint64 // Estimated input bandwidth bytes/sec (float64 bits)
SendRateEstSentBW atomic.Uint64 // Estimated sent bandwidth bytes/sec (float64 bits)
SendRatePktRetransRate atomic.Uint64 // Retransmission rate percentage (float64 bits)
// Light ACK threshold counter - replaces nPackets in receiver
// Used to determine when to send a "light" ACK vs full ACK
RecvLightACKCounter atomic.Uint64 // Packets since last ACK (for light ACK threshold)
EventLoopIterations atomic.Uint64 // Total loop iterations
EventLoopFullACKFires atomic.Uint64 // Times fullACKTicker.C case executed
EventLoopNAKFires atomic.Uint64 // Times nakTicker.C case executed
EventLoopRateFires atomic.Uint64 // Times rateTicker.C case executed
EventLoopDefaultRuns atomic.Uint64 // Times default case executed
EventLoopIdleBackoffs atomic.Uint64 // Times idle backoff sleep triggered
EventLoopControlProcessed atomic.Uint64 // Connection control packets processed (ACKACK, KEEPALIVE)
// Startup diagnostics (debug intermittent failures)
EventLoopEntered atomic.Uint64 // Times EventLoop() was called
EventLoopExitedEarly atomic.Uint64 // Times EventLoop returned early (useEventLoop=false)
EventLoopExitedNoRing atomic.Uint64 // Times EventLoop returned early (packetRing=nil)
AckBtreeSize atomic.Uint64 // Current size of ack btree (gauge)
AckBtreeEntriesExpired atomic.Uint64 // Entries expired by ExpireOlderThan
AckBtreeUnknownACKACK atomic.Uint64 // ACKACK received for unknown ackNum
RTTMicroseconds atomic.Uint64 // Current RTT value in microseconds (EWMA smoothed)
RTTVarMicroseconds atomic.Uint64 // Current RTT variance in microseconds (EWMA smoothed)
RTTLastSampleMicroseconds atomic.Uint64 // Last RTT sample in microseconds (NO smoothing, raw value)
// Per-ring metrics for send path (connection_linux.go)
IoUringSendRingMetrics []*IoUringRingMetrics
IoUringSendRingCount int // Number of send rings
// Per-ring metrics for dialer recv path (dial_linux.go)
IoUringDialerRecvRingMetrics []*IoUringRingMetrics
IoUringDialerRecvRingCount int // Number of dialer recv rings
}
ConnectionMetrics holds all metrics for a single connection All counters use atomic.Uint64 for lock-free, high-performance increments
func NewConnectionMetrics ¶
func NewConnectionMetrics() *ConnectionMetrics
NewConnectionMetrics creates a new ConnectionMetrics with LockTiming initialized. All atomic counters are zero-initialized automatically.
func (*ConnectionMetrics) GetRecvRateBytesPerSec ¶
func (m *ConnectionMetrics) GetRecvRateBytesPerSec() float64
GetRecvRateBytesPerSec returns bytes per second as float64
func (*ConnectionMetrics) GetRecvRateMbps ¶
func (m *ConnectionMetrics) GetRecvRateMbps() float64
GetRecvRateMbps returns receive rate in megabits per second
func (*ConnectionMetrics) GetRecvRatePacketsPerSec ¶
func (m *ConnectionMetrics) GetRecvRatePacketsPerSec() float64
GetRecvRatePacketsPerSec returns packets per second as float64
func (*ConnectionMetrics) GetRecvRateRetransPercent ¶
func (m *ConnectionMetrics) GetRecvRateRetransPercent() float64
GetRecvRateRetransPercent returns retransmission percentage
func (*ConnectionMetrics) GetSendRateEstInputBW ¶
func (m *ConnectionMetrics) GetSendRateEstInputBW() float64
GetSendRateEstInputBW returns estimated input bandwidth in bytes/sec
func (*ConnectionMetrics) GetSendRateEstSentBW ¶
func (m *ConnectionMetrics) GetSendRateEstSentBW() float64
GetSendRateEstSentBW returns estimated sent bandwidth in bytes/sec
func (*ConnectionMetrics) GetSendRateMbps ¶
func (m *ConnectionMetrics) GetSendRateMbps() float64
GetSendRateMbps returns sent rate in megabits per second
func (*ConnectionMetrics) GetSendRateRetransPercent ¶
func (m *ConnectionMetrics) GetSendRateRetransPercent() float64
GetSendRateRetransPercent returns sender retransmission percentage
type DropReason ¶
type DropReason uint8
DropReason represents the reason for dropping a packet Using an enum type instead of strings for better performance
const ( // Receiver drop reasons DropReasonTooOld DropReason = iota DropReasonAlreadyAcked DropReasonDuplicate DropReasonStoreInsertFailed // Sender drop reasons DropReasonTooOldSend // Same as TooOld but for sender path // Error drop reasons (both receive and send) DropReasonMarshal DropReasonRingFull DropReasonSubmit DropReasonIoUring DropReasonParse DropReasonRoute DropReasonEmpty DropReasonWrite // Write error (generic I/O error) DropReasonWrongPeer // Wrong peer address DropReasonUnknownSocket // Unknown socket ID DropReasonNilConnection // Nil connection DropReasonBacklogFull // Handshake backlog full DropReasonQueueFull // Receive queue full )
func (DropReason) String ¶
func (r DropReason) String() string
String returns the string representation of the drop reason (for Prometheus labels)
type IoUringRingMetrics ¶
type IoUringRingMetrics struct {
// Submit metrics
SubmitSuccess atomic.Uint64 // Submit() succeeded
SubmitRingFull atomic.Uint64 // GetSQE returned nil (ring full)
SubmitError atomic.Uint64 // Submit() failed
GetSQERetries atomic.Uint64 // GetSQE required retry
SubmitRetries atomic.Uint64 // Submit() required retry (EINTR/EAGAIN)
// Completion metrics
CompletionSuccess atomic.Uint64 // WaitCQETimeout returned a completion
CompletionTimeout atomic.Uint64 // ETIME: timeout expired (healthy)
CompletionEBADF atomic.Uint64 // Ring closed (normal shutdown)
CompletionEINTR atomic.Uint64 // Interrupted by signal
CompletionError atomic.Uint64 // Other unexpected errors
CompletionCtxCancelled atomic.Uint64 // Context canceled (shutdown)
// Packet processing
PacketsProcessed atomic.Uint64 // Packets successfully processed
BytesProcessed atomic.Uint64 // Bytes processed
}
IoUringRingMetrics holds metrics for a single io_uring ring. Each ring has its own instance to avoid cache-line contention across cores. See multi_iouring_design.md Section 5.2 for design rationale.
func NewIoUringRingMetrics ¶
func NewIoUringRingMetrics(ringCount int) []*IoUringRingMetrics
NewIoUringRingMetrics creates metrics for the specified number of rings. Returns nil if ringCount <= 1 (use existing single-ring metrics for backward compatibility). NewIoUringRingMetrics creates metrics for the specified number of rings. ALWAYS creates the array, even for ringCount=1 (unified approach). This simplifies code by removing conditional "use old vs new" logic.
type ListenerMetrics ¶
type ListenerMetrics struct {
// RecvConnLookupNotFound increments when listen.go reader() receives a packet
// with a DestinationSocketId that doesn't match any known connection.
RecvConnLookupNotFound atomic.Uint64
// RecvConnLookupNotFoundIoUring increments when listen_linux.go io_uring path
// receives a packet with a socket ID that doesn't match any known connection.
RecvConnLookupNotFoundIoUring atomic.Uint64
// HandshakeRejectNotFound increments when Reject() is called on a connection
// request that doesn't exist in connReqs map. This is a programming error.
HandshakeRejectNotFound atomic.Uint64
// HandshakeAcceptNotFound increments when Accept() is called on a connection
// request that doesn't exist in connReqs map. This is a programming error.
HandshakeAcceptNotFound atomic.Uint64
// HandshakeDuplicateRequest increments when a duplicate handshake request
// is received (same SRTSocketId as an existing pending request).
HandshakeDuplicateRequest atomic.Uint64
// SocketIdCollision increments when generateSocketId() finds a randomly
// generated socket ID is already in use in the conns map.
SocketIdCollision atomic.Uint64
// SendConnLookupNotFound increments when listener.send() tries to look up
// a connection by DestinationSocketId and fails. This indicates Bug 3.
// Should always be 0 with the closure-based fix in place.
SendConnLookupNotFound atomic.Uint64
// ConnectionsActive is a gauge tracking current active connections.
// Uses Int64 to support Add(-1) for decrements. Lock-free atomic.
ConnectionsActive atomic.Int64
// ConnectionsEstablished increments when RegisterConnection() is called.
// This is the total count of connections established over the listener lifetime.
ConnectionsEstablished atomic.Uint64
// ConnectionsClosedTotal is the total count of all closed connections.
// Should equal ConnectionsEstablished at test end (no leaks).
ConnectionsClosedTotal atomic.Uint64
// ConnectionsClosed tracks connections closed by reason.
// These help identify unexpected connection terminations during tests.
// Sum of all reasons should equal ConnectionsClosedTotal.
ConnectionsClosedGraceful atomic.Uint64 // Normal shutdown (Close() called)
ConnectionsClosedPeerIdle atomic.Uint64 // Peer idle timeout expired
ConnectionsClosedContextCancel atomic.Uint64 // Parent context canceled
ConnectionsClosedError atomic.Uint64 // Error during operation
// Per-ring metrics for listener recv path (listen_linux.go)
IoUringRecvRingMetrics []*IoUringRingMetrics
IoUringRecvRingCount int // Number of listener recv rings (for gauge export)
}
ListenerMetrics holds listener-level metrics (not per-connection). These track events that happen before a connection is established or after a connection is closed, where we cannot associate with a specific connection.
Use cases: - Detect silent failures in map lookups (Bug 3 style issues) - Monitor for attacks or malformed packets targeting unknown connections - Track handshake anomalies
func GetListenerMetrics ¶
func GetListenerMetrics() *ListenerMetrics
GetListenerMetrics returns the global listener metrics instance. This is safe to call concurrently - all fields are atomic.
func NewListenerMetrics ¶
func NewListenerMetrics() *ListenerMetrics
NewListenerMetrics creates a new ListenerMetrics instance with all counters at zero.
func (*ListenerMetrics) InitListenerRecvRingMetrics ¶
func (lm *ListenerMetrics) InitListenerRecvRingMetrics(ringCount int)
InitListenerRecvRingMetrics initializes per-ring metrics for the listener. ALWAYS creates the per-ring array, even for ringCount=1 (unified approach). Call this from io_uring initialization. Safe to call multiple times.
type LockTimingMetrics ¶
type LockTimingMetrics struct {
// contains filtered or unexported fields
}
LockTimingMetrics tracks lock hold and wait times Uses lock-free ring buffer with atomic values for maximum performance
func (*LockTimingMetrics) GetStats ¶
func (ltm *LockTimingMetrics) GetStats() (holdAvg, holdMax, waitAvg, waitMax float64)
GetStats returns average and max hold/wait times All reads are lock-free (atomic operations only)
Performance note: For 10 values, a simple loop is optimal. The Go compiler may auto-vectorize this, and the overhead of SIMD setup (if we used assembly/cgo) would likely exceed the benefit.
func (*LockTimingMetrics) GetTotalAcquisitions ¶
func (ltm *LockTimingMetrics) GetTotalAcquisitions() uint64
GetTotalAcquisitions returns the total number of lock acquisitions Uses holdTimeIndex as a proxy (saves an atomic operation)
func (*LockTimingMetrics) RecordHoldTime ¶
func (ltm *LockTimingMetrics) RecordHoldTime(duration time.Duration)
RecordHoldTime records a lock hold time measurement
func (*LockTimingMetrics) RecordWaitTime ¶
func (ltm *LockTimingMetrics) RecordWaitTime(duration time.Duration)
RecordWaitTime records a lock wait time measurement
func (*LockTimingMetrics) SnapshotHoldTimes ¶
func (ltm *LockTimingMetrics) SnapshotHoldTimes() [LockTimingSamples]int64
SnapshotHoldTimes returns a snapshot of all hold time samples (for debugging)
func (*LockTimingMetrics) SnapshotWaitTimes ¶
func (ltm *LockTimingMetrics) SnapshotWaitTimes() [LockTimingSamples]int64
SnapshotWaitTimes returns a snapshot of all wait time samples (for debugging)
type MetricsGetter ¶
type MetricsGetter func(ctx context.Context) (StabilizationMetrics, error)
MetricsGetter is a function that returns current stabilization metrics. Used to abstract over different ways of getting metrics (HTTP/UDS fetch). The context allows cancellation of in-flight requests during shutdown.
func NewHTTPGetter ¶
func NewHTTPGetter(url string) MetricsGetter
NewHTTPGetter creates a MetricsGetter that fetches from an HTTP URL. The URL should point to the /stabilize endpoint.
Example:
getter := metrics.NewHTTPGetter("http://localhost:5101/stabilize")
func NewUDSGetter ¶
func NewUDSGetter(socketPath string) MetricsGetter
NewUDSGetter creates a MetricsGetter that fetches from a Unix Domain Socket. The socketPath should be the path to the UDS file.
Example:
getter := metrics.NewUDSGetter("/tmp/server-metrics.sock")
type MetricsRegistry ¶
type MetricsRegistry struct {
// contains filtered or unexported fields
}
MetricsRegistry holds all connection metrics
type NAKCounterType ¶
type NAKCounterType int
NAKCounterType specifies which counter set to increment.
const ( // NAKCounterSend is used when the RECEIVER generates and sends NAKs. // Increments: CongestionRecvNAKSingle, CongestionRecvNAKRange, CongestionRecvNAKPktsTotal NAKCounterSend NAKCounterType = iota // NAKCounterRecv is used when the SENDER receives NAKs. // Increments: CongestionSendNAKSingleRecv, CongestionSendNAKRangeRecv, CongestionSendNAKPktsRecv NAKCounterRecv )
type ProcStat ¶
type ProcStat struct {
UserTime uint64 // Field 14: utime - user mode jiffies
SystemTime uint64 // Field 15: stime - kernel mode jiffies
}
ProcStat holds parsed CPU time values from /proc/self/stat. Times are in jiffies (typically 1/100th of a second on Linux).
func ReadProcStat ¶
ReadProcStat reads and parses /proc/self/stat to extract CPU time. Returns user and system time in jiffies (1/100th second on most Linux). Zero allocations in the parsing hot path.
type StabilizationConfig ¶
type StabilizationConfig struct {
// PollInterval is how often to check metrics (default: 100ms)
PollInterval time.Duration
// StableCount is how many consecutive unchanged polls required (default: 2)
StableCount int
// MaxWait is the maximum time to wait before giving up (default: 5s)
MaxWait time.Duration
}
StabilizationConfig configures the stabilization detection behavior.
func DefaultStabilizationConfig ¶
func DefaultStabilizationConfig() StabilizationConfig
DefaultStabilizationConfig returns sensible defaults for stabilization detection.
type StabilizationMetrics ¶
type StabilizationMetrics struct {
DataSent uint64 // Packets sent (data)
DataRecv uint64 // Packets received (data)
AckSent uint64 // ACKs sent
AckRecv uint64 // ACKs received
NakSent uint64 // NAKs sent (loss reports)
NakRecv uint64 // NAKs received (retransmit requests)
}
StabilizationMetrics holds the 6 key counters we monitor for stabilization. These are the metrics that change during active data transfer and should stop changing once the pipeline has drained.
func AggregateStabilizationMetrics ¶
func AggregateStabilizationMetrics(all ...StabilizationMetrics) StabilizationMetrics
AggregateStabilizationMetrics combines metrics from multiple sources into one. This is useful when you want to check if all components have stabilized together.
func GetStabilizationMetricsFromRegistry ¶
func GetStabilizationMetricsFromRegistry() StabilizationMetrics
GetStabilizationMetricsFromRegistry extracts stabilization-relevant metrics aggregated across all connections in the registry.
func ParseStabilizationResponse ¶
func ParseStabilizationResponse(response string) (StabilizationMetrics, error)
ParseStabilizationResponse parses the response from /stabilize endpoint. Returns error if any required metric is missing or malformed.
func (StabilizationMetrics) Equal ¶
func (s StabilizationMetrics) Equal(other StabilizationMetrics) bool
Equal returns true if two StabilizationMetrics are identical. This is used to detect when metrics have stopped changing.
func (StabilizationMetrics) String ¶
func (s StabilizationMetrics) String() string
String returns a human-readable representation of the metrics.
type StabilizationResult ¶
type StabilizationResult struct {
// Stable indicates whether stabilization was achieved
Stable bool
// Elapsed is the time spent waiting
Elapsed time.Duration
// Iterations is the number of poll cycles performed
Iterations int
// FinalMetrics contains the last metrics snapshot from each getter
FinalMetrics []StabilizationMetrics
// Error is set if stabilization failed due to an error (not timeout)
Error error
}
StabilizationResult contains the result of waiting for stabilization.
func WaitForStabilization ¶
func WaitForStabilization(ctx context.Context, cfg StabilizationConfig, getters ...MetricsGetter) StabilizationResult
WaitForStabilization waits until metrics from all getters stop changing. It polls each getter at the configured interval and checks if all metrics are unchanged for the required number of consecutive polls.
Returns a StabilizationResult indicating whether stabilization was achieved. The context can be used to cancel the wait early.