рабочий вариант, но скороть 10 МБит
This commit is contained in:
@@ -11,8 +11,13 @@ const (
|
||||
Magic uint32 = 0x52415046 // RAPF
|
||||
Version uint8 = 1
|
||||
|
||||
HeaderSize = 32
|
||||
DefaultMaxPayload = 1024 * 1024
|
||||
HeaderSize = 32
|
||||
|
||||
// DefaultMaxPayload is a per-frame guardrail, not a throughput limit.
|
||||
// Fabric services must scale by many QUIC streams and many frames; keeping
|
||||
// this above common VPN/RDP/VNC burst batches avoids a hidden 1 MiB choke
|
||||
// while still bounding memory for a single decoded frame.
|
||||
DefaultMaxPayload = 8 * 1024 * 1024
|
||||
)
|
||||
|
||||
type FrameType uint8
|
||||
|
||||
@@ -102,6 +102,26 @@ func TestRejectsOversizedPayload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultPayloadAllowsMultiMegabyteServiceBatches(t *testing.T) {
|
||||
payload := bytes.Repeat([]byte("x"), 2*1024*1024)
|
||||
frame := Frame{
|
||||
Type: FrameData,
|
||||
StreamID: 1,
|
||||
Payload: payload,
|
||||
}
|
||||
encoded, err := MarshalFrame(frame)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal multi-megabyte frame: %v", err)
|
||||
}
|
||||
decoded, err := UnmarshalFrame(encoded, DefaultMaxPayload)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal multi-megabyte frame: %v", err)
|
||||
}
|
||||
if len(decoded.Payload) != len(payload) {
|
||||
t.Fatalf("payload length = %d, want %d", len(decoded.Payload), len(payload))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectsUnknownTrafficClass(t *testing.T) {
|
||||
frame := Frame{
|
||||
Type: FrameOpenStream,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
const (
|
||||
DefaultInitialStreamCredit = 32
|
||||
DefaultMaxStreamCredit = 4096
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -29,6 +30,7 @@ const (
|
||||
|
||||
type SessionConfig struct {
|
||||
InitialStreamCredit int
|
||||
MaxStreamCredit int
|
||||
ClassQueueCapacity map[TrafficClass]int
|
||||
}
|
||||
|
||||
@@ -188,6 +190,7 @@ func (s *Session) Ack(streamID uint64, sequence uint64) error {
|
||||
delta := sequence - st.metrics.Acked
|
||||
st.metrics.Acked = sequence
|
||||
s.metrics.FramesAcked += delta
|
||||
st.credit = minInt(st.credit+int(delta), s.cfg.MaxStreamCredit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -205,7 +208,7 @@ func (s *Session) AddCredit(streamID uint64, frames int) error {
|
||||
if st.state != StreamStateOpen {
|
||||
return ErrStreamClosed
|
||||
}
|
||||
st.credit += frames
|
||||
st.credit = minInt(st.credit+frames, s.cfg.MaxStreamCredit)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -311,6 +314,12 @@ func normalizeSessionConfig(cfg SessionConfig) SessionConfig {
|
||||
if cfg.InitialStreamCredit <= 0 {
|
||||
cfg.InitialStreamCredit = DefaultInitialStreamCredit
|
||||
}
|
||||
if cfg.MaxStreamCredit <= 0 {
|
||||
cfg.MaxStreamCredit = maxInt(DefaultMaxStreamCredit, cfg.InitialStreamCredit)
|
||||
}
|
||||
if cfg.InitialStreamCredit > cfg.MaxStreamCredit {
|
||||
cfg.InitialStreamCredit = cfg.MaxStreamCredit
|
||||
}
|
||||
if cfg.ClassQueueCapacity == nil {
|
||||
cfg.ClassQueueCapacity = map[TrafficClass]int{}
|
||||
}
|
||||
@@ -331,14 +340,28 @@ func priorityOrder() []TrafficClass {
|
||||
func defaultClassQueueCapacity(trafficClass TrafficClass) int {
|
||||
switch trafficClass {
|
||||
case TrafficClassControl, TrafficClassDNS, TrafficClassInteractive:
|
||||
return 128
|
||||
return 1024
|
||||
case TrafficClassReliable:
|
||||
return 64
|
||||
return 512
|
||||
case TrafficClassBulk:
|
||||
return 16
|
||||
return 256
|
||||
case TrafficClassDroppable:
|
||||
return 8
|
||||
return 128
|
||||
default:
|
||||
return 32
|
||||
return 256
|
||||
}
|
||||
}
|
||||
|
||||
func minInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -129,20 +129,36 @@ func TestSessionResetDropsOnlySelectedStream(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSessionAckUpdatesMetrics(t *testing.T) {
|
||||
session := NewSession(SessionConfig{})
|
||||
session := NewSession(SessionConfig{InitialStreamCredit: 2})
|
||||
mustOpenStream(t, session, 1, TrafficClassReliable)
|
||||
mustEnqueue(t, session, 1, "one")
|
||||
mustEnqueue(t, session, 1, "two")
|
||||
if _, err := session.EnqueueData(1, []byte("blocked")); !errors.Is(err, ErrStreamCreditExhausted) {
|
||||
t.Fatalf("credit error = %v, want %v", err, ErrStreamCreditExhausted)
|
||||
}
|
||||
|
||||
if err := session.Ack(1, 2); err != nil {
|
||||
t.Fatalf("ack: %v", err)
|
||||
}
|
||||
mustEnqueue(t, session, 1, "three")
|
||||
snapshot := session.Snapshot()
|
||||
if snapshot.FramesAcked != 2 || snapshot.Streams[1].Acked != 2 {
|
||||
if snapshot.FramesAcked != 2 || snapshot.Streams[1].Acked != 2 || snapshot.Streams[1].Credit != 1 {
|
||||
t.Fatalf("ack metrics = %+v stream=%+v", snapshot, snapshot.Streams[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionCreditIsCapped(t *testing.T) {
|
||||
session := NewSession(SessionConfig{InitialStreamCredit: 1, MaxStreamCredit: 2})
|
||||
mustOpenStream(t, session, 1, TrafficClassReliable)
|
||||
if err := session.AddCredit(1, 100); err != nil {
|
||||
t.Fatalf("add credit: %v", err)
|
||||
}
|
||||
snapshot := session.Snapshot()
|
||||
if snapshot.Streams[1].Credit != 2 {
|
||||
t.Fatalf("credit = %d, want cap 2", snapshot.Streams[1].Credit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionCloseRejectsNewData(t *testing.T) {
|
||||
session := NewSession(SessionConfig{})
|
||||
mustOpenStream(t, session, 1, TrafficClassReliable)
|
||||
|
||||
Reference in New Issue
Block a user