first
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package scheduler
|
||||
|
||||
// This file demonstrates how to add a custom scheduler.
|
||||
// To create your own:
|
||||
// 1. Copy this file and rename it (e.g., weighted_rtt.go)
|
||||
// 2. Implement the three PathScheduler methods
|
||||
// 3. Update the init() to register with your scheduler name
|
||||
//
|
||||
// The scheduler will automatically appear in --list-schedulers.
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
quic "github.com/AeonDave/mp-quic-go"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("weighted", func() quic.PathScheduler {
|
||||
return NewWeightedScheduler()
|
||||
})
|
||||
}
|
||||
|
||||
// WeightedScheduler is an example custom scheduler that weighs paths
|
||||
// by a combination of RTT and available congestion window.
|
||||
type WeightedScheduler struct {
|
||||
mu sync.Mutex
|
||||
quotas map[quic.PathID]uint64
|
||||
}
|
||||
|
||||
// NewWeightedScheduler creates a new weighted scheduler.
|
||||
func NewWeightedScheduler() *WeightedScheduler {
|
||||
return &WeightedScheduler{
|
||||
quotas: make(map[quic.PathID]uint64),
|
||||
}
|
||||
}
|
||||
|
||||
// SelectPath picks the path with the best weighted score.
|
||||
// Score = (CongestionWindow - BytesInFlight) / (1 + SmoothedRTT_ms)
|
||||
// Higher score = more capacity available per unit latency.
|
||||
func (s *WeightedScheduler) SelectPath(paths []quic.SchedulerPathInfo, hasRetransmission bool) *quic.SchedulerPathInfo {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(paths) == 1 {
|
||||
if !hasRetransmission && !paths[0].SendingAllowed {
|
||||
return nil
|
||||
}
|
||||
return &paths[0]
|
||||
}
|
||||
|
||||
var best *quic.SchedulerPathInfo
|
||||
var bestScore float64 = -1
|
||||
|
||||
for i := range paths {
|
||||
p := &paths[i]
|
||||
if !hasRetransmission && !p.SendingAllowed {
|
||||
continue
|
||||
}
|
||||
if p.PotentiallyFailed {
|
||||
continue
|
||||
}
|
||||
|
||||
// Available window
|
||||
available := float64(0)
|
||||
if p.CongestionWindow > p.BytesInFlight {
|
||||
available = float64(p.CongestionWindow - p.BytesInFlight)
|
||||
}
|
||||
|
||||
// RTT factor (ms, minimum 1 to avoid division by zero)
|
||||
rttMs := float64(1)
|
||||
if p.SmoothedRTT.Milliseconds() > 0 {
|
||||
rttMs = float64(p.SmoothedRTT.Milliseconds())
|
||||
}
|
||||
|
||||
score := available / rttMs
|
||||
if score > bestScore {
|
||||
bestScore = score
|
||||
best = p
|
||||
}
|
||||
}
|
||||
|
||||
return best
|
||||
}
|
||||
|
||||
// UpdateQuota tracks per-path send counts.
|
||||
func (s *WeightedScheduler) UpdateQuota(pathID quic.PathID, packetSize quic.ByteCount) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.quotas[pathID]++
|
||||
}
|
||||
|
||||
// Reset clears all state.
|
||||
func (s *WeightedScheduler) Reset() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.quotas = make(map[quic.PathID]uint64)
|
||||
}
|
||||
Reference in New Issue
Block a user