Source File
writesched_priority.go
Belonging Package
golang.org/x/net/http2
package http2
import (
)
const priorityDefaultWeight = 15 // 16 = 15 + 1
func ( *PriorityWriteSchedulerConfig) WriteScheduler {
= &PriorityWriteSchedulerConfig{
MaxClosedNodesInTree: 10,
MaxIdleNodesInTree: 10,
ThrottleOutOfOrderWrites: false,
}
}
:= &priorityWriteScheduler{
nodes: make(map[uint32]*priorityNode),
maxClosedNodesInTree: .MaxClosedNodesInTree,
maxIdleNodesInTree: .MaxIdleNodesInTree,
enableWriteThrottle: .ThrottleOutOfOrderWrites,
}
.nodes[0] = &.root
if .ThrottleOutOfOrderWrites {
.writeThrottleLimit = 1024
} else {
.writeThrottleLimit = math.MaxInt32
}
return
}
type priorityNodeState int
const (
priorityNodeOpen priorityNodeState = iota
priorityNodeClosed
priorityNodeIdle
)
type priorityNode struct {
q writeQueue // queue of pending frames to write
id uint32 // id of the stream, or 0 for the root of the tree
weight uint8 // the actual weight is weight+1, so the value is in [1,256]
state priorityNodeState // open | closed | idle
bytes int64 // number of bytes written by this node, or 0 if closed
subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
parent *priorityNode
kids *priorityNode // start of the kids list
prev, next *priorityNode // doubly-linked list of siblings
}
func ( *priorityNode) ( *priorityNode) {
if == {
panic("setParent to self")
}
if .parent == {
return
func ( *priorityNode) ( bool, *[]*priorityNode, func(*priorityNode, bool) bool) bool {
if !.q.empty() && (, ) {
return true
}
if .kids == nil {
return false
}
if .id != 0 {
= || (.state == priorityNodeOpen)
}
* = (*)[:0]
for .kids != nil {
* = append(*, .kids)
.kids.setParent(nil)
}
sort.Sort(sortPriorityNodeSiblings(*))
for := len(*) - 1; >= 0; -- {
(*)[].setParent() // setParent inserts at the head of n.kids
}
for := .kids; != nil; = .next {
if .(, , ) {
return true
}
}
return false
}
type sortPriorityNodeSiblings []*priorityNode
func ( sortPriorityNodeSiblings) () int { return len() }
func ( sortPriorityNodeSiblings) (, int) { [], [] = [], [] }
, := float64([].weight+1), float64([].subtreeBytes)
, := float64([].weight+1), float64([].subtreeBytes)
if == 0 && == 0 {
return >=
}
if == 0 {
return false
}
return / <= /
}
nodes map[uint32]*priorityNode
tmp []*priorityNode
if := .nodes[]; != nil {
if .state != priorityNodeIdle {
panic(fmt.Sprintf("stream %d already opened", ))
}
.state = priorityNodeOpen
return
}
:= .nodes[.PusherID]
if == nil {
= &.root
}
:= &priorityNode{
q: *.queuePool.get(),
id: ,
weight: priorityDefaultWeight,
state: priorityNodeOpen,
}
.setParent()
.nodes[] =
if > .maxID {
.maxID =
}
}
func ( *priorityWriteScheduler) ( uint32) {
if == 0 {
panic("violation of WriteScheduler interface: cannot close stream 0")
}
if .nodes[] == nil {
panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", ))
}
if .nodes[].state != priorityNodeOpen {
panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", ))
}
:= .nodes[]
.state = priorityNodeClosed
.addBytes(-.bytes)
:= .q
.queuePool.put(&)
.q.s = nil
if .maxClosedNodesInTree > 0 {
.addClosedOrIdleNode(&.closedNodes, .maxClosedNodesInTree, )
} else {
.removeNode()
}
}
func ( *priorityWriteScheduler) ( uint32, PriorityParam) {
if == 0 {
panic("adjustPriority on root")
}
:= .nodes[]
if == nil {
if <= .maxID || .maxIdleNodesInTree == 0 {
return
}
.maxID =
= &priorityNode{
q: *.queuePool.get(),
id: ,
weight: priorityDefaultWeight,
state: priorityNodeIdle,
}
.setParent(&.root)
.nodes[] =
.addClosedOrIdleNode(&.idleNodes, .maxIdleNodesInTree, )
}
if == {
return
}
if .Exclusive {
:= .kids
for != nil {
:= .next
if != {
.setParent()
}
=
}
}
.setParent()
.weight = .Weight
}
func ( *priorityWriteScheduler) ( FrameWriteRequest) {
var *priorityNode
if := .StreamID(); == 0 {
= &.root
} else {
= .nodes[]
if .DataSize() > 0 {
panic("add DATA on non-open stream")
}
= &.root
}
}
.q.push()
}
func ( *priorityWriteScheduler) () ( FrameWriteRequest, bool) {
.root.walkReadyInOrder(false, &.tmp, func( *priorityNode, bool) bool {
:= int32(math.MaxInt32)
if {
= .writeThrottleLimit
}
, = .q.consume()
if ! {
return false
}
if {
.writeThrottleLimit += 1024
if .writeThrottleLimit < 0 {
.writeThrottleLimit = math.MaxInt32
}
} else if .enableWriteThrottle {
.writeThrottleLimit = 1024
}
return true
})
return ,
}
func ( *priorityWriteScheduler) ( *[]*priorityNode, int, *priorityNode) {
if == 0 {
return
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |