forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/golang.org/x/net/http2/writesched_roundrobin.go

209 lines
2.8 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Copyright 2023 The Go Authors. All rights reserved.
2024-02-18 10:42:21 +00:00
// Use of this source code is governed by a BSD-style
2024-02-18 10:42:21 +00:00
// license that can be found in the LICENSE file.
package http2
import (
"fmt"
"math"
)
type roundRobinWriteScheduler struct {
2024-02-18 10:42:21 +00:00
// control contains control frames (SETTINGS, PING, etc.).
2024-02-18 10:42:21 +00:00
control writeQueue
// streams maps stream ID to a queue.
2024-02-18 10:42:21 +00:00
streams map[uint32]*writeQueue
// stream queues are stored in a circular linked list.
2024-02-18 10:42:21 +00:00
// head is the next stream to write, or nil if there are no streams open.
2024-02-18 10:42:21 +00:00
head *writeQueue
// pool of empty queues for reuse.
2024-02-18 10:42:21 +00:00
queuePool writeQueuePool
}
// newRoundRobinWriteScheduler constructs a new write scheduler.
2024-02-18 10:42:21 +00:00
// The round robin scheduler priorizes control frames
2024-02-18 10:42:21 +00:00
// like SETTINGS and PING over DATA frames.
2024-02-18 10:42:21 +00:00
// When there are no control frames to send, it performs a round-robin
2024-02-18 10:42:21 +00:00
// selection from the ready streams.
2024-02-18 10:42:21 +00:00
func newRoundRobinWriteScheduler() WriteScheduler {
2024-02-18 10:42:21 +00:00
ws := &roundRobinWriteScheduler{
2024-02-18 10:42:21 +00:00
streams: make(map[uint32]*writeQueue),
}
2024-02-18 10:42:21 +00:00
return ws
2024-02-18 10:42:21 +00:00
}
func (ws *roundRobinWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
2024-02-18 10:42:21 +00:00
if ws.streams[streamID] != nil {
2024-02-18 10:42:21 +00:00
panic(fmt.Errorf("stream %d already opened", streamID))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
q := ws.queuePool.get()
2024-02-18 10:42:21 +00:00
ws.streams[streamID] = q
2024-02-18 10:42:21 +00:00
if ws.head == nil {
2024-02-18 10:42:21 +00:00
ws.head = q
2024-02-18 10:42:21 +00:00
q.next = q
2024-02-18 10:42:21 +00:00
q.prev = q
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
// Queues are stored in a ring.
2024-02-18 10:42:21 +00:00
// Insert the new stream before ws.head, putting it at the end of the list.
2024-02-18 10:42:21 +00:00
q.prev = ws.head.prev
2024-02-18 10:42:21 +00:00
q.next = ws.head
2024-02-18 10:42:21 +00:00
q.prev.next = q
2024-02-18 10:42:21 +00:00
q.next.prev = q
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (ws *roundRobinWriteScheduler) CloseStream(streamID uint32) {
2024-02-18 10:42:21 +00:00
q := ws.streams[streamID]
2024-02-18 10:42:21 +00:00
if q == nil {
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.next == q {
2024-02-18 10:42:21 +00:00
// This was the only open stream.
2024-02-18 10:42:21 +00:00
ws.head = nil
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
q.prev.next = q.next
2024-02-18 10:42:21 +00:00
q.next.prev = q.prev
2024-02-18 10:42:21 +00:00
if ws.head == q {
2024-02-18 10:42:21 +00:00
ws.head = q.next
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
delete(ws.streams, streamID)
2024-02-18 10:42:21 +00:00
ws.queuePool.put(q)
2024-02-18 10:42:21 +00:00
}
func (ws *roundRobinWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {}
func (ws *roundRobinWriteScheduler) Push(wr FrameWriteRequest) {
2024-02-18 10:42:21 +00:00
if wr.isControl() {
2024-02-18 10:42:21 +00:00
ws.control.push(wr)
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
q := ws.streams[wr.StreamID()]
2024-02-18 10:42:21 +00:00
if q == nil {
2024-02-18 10:42:21 +00:00
// This is a closed stream.
2024-02-18 10:42:21 +00:00
// wr should not be a HEADERS or DATA frame.
2024-02-18 10:42:21 +00:00
// We push the request onto the control queue.
2024-02-18 10:42:21 +00:00
if wr.DataSize() > 0 {
2024-02-18 10:42:21 +00:00
panic("add DATA on non-open stream")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
ws.control.push(wr)
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
q.push(wr)
2024-02-18 10:42:21 +00:00
}
func (ws *roundRobinWriteScheduler) Pop() (FrameWriteRequest, bool) {
2024-02-18 10:42:21 +00:00
// Control and RST_STREAM frames first.
2024-02-18 10:42:21 +00:00
if !ws.control.empty() {
2024-02-18 10:42:21 +00:00
return ws.control.shift(), true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if ws.head == nil {
2024-02-18 10:42:21 +00:00
return FrameWriteRequest{}, false
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
q := ws.head
2024-02-18 10:42:21 +00:00
for {
2024-02-18 10:42:21 +00:00
if wr, ok := q.consume(math.MaxInt32); ok {
2024-02-18 10:42:21 +00:00
ws.head = q.next
2024-02-18 10:42:21 +00:00
return wr, true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
q = q.next
2024-02-18 10:42:21 +00:00
if q == ws.head {
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return FrameWriteRequest{}, false
2024-02-18 10:42:21 +00:00
}