mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
This adds an interface to support pluggable schedulers. The interface is defined in writesched.go. The only type needed by this interface is FrameWriteRequest, which describes a request to write a frame (this used to be called frameWriteMsg). The scheduler can be configured with a new field in http2.Server. Two schedulers are implemented: 1) A random scheduler that is essentially equivalent to the existing scheduler. This is currently the default scheduler if none is configured. The implementation is in writesched_random.go. 2) A scheduler that uses H2 weights and priorities. The H2 priority tree is maintained as a tree of priorityNodes. The next frame is chosen by walking this tree in topological order, where sibling nodes are ordered by their bandwidth usage relative to their H2 weight. Two optional features are added to improve performance -- these are configured with PriorityWriteSchedulerConfig. Fixes golang/go#16168 Change-Id: I97ec93e5c58c2efec35455ba2f3c31e849f706af Reviewed-on: https://go-review.googlesource.com/25366 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
// Copyright 2014 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package http2
|
|
|
|
import "math"
|
|
|
|
// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
|
|
// priorities. Control frames like SETTINGS and PING are written before DATA
|
|
// frames, but if no control frames are queued and multiple streams have queued
|
|
// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
|
|
func NewRandomWriteScheduler() WriteScheduler {
|
|
return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
|
|
}
|
|
|
|
type randomWriteScheduler struct {
|
|
// zero are frames not associated with a specific stream.
|
|
zero writeQueue
|
|
|
|
// sq contains the stream-specific queues, keyed by stream ID.
|
|
// When a stream is idle or closed, it's deleted from the map.
|
|
sq map[uint32]*writeQueue
|
|
|
|
// pool of empty queues for reuse.
|
|
queuePool writeQueuePool
|
|
}
|
|
|
|
func (ws *randomWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
|
|
// no-op: idle streams are not tracked
|
|
}
|
|
|
|
func (ws *randomWriteScheduler) CloseStream(streamID uint32) {
|
|
q, ok := ws.sq[streamID]
|
|
if !ok {
|
|
return
|
|
}
|
|
delete(ws.sq, streamID)
|
|
ws.queuePool.put(q)
|
|
}
|
|
|
|
func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
|
|
// no-op: priorities are ignored
|
|
}
|
|
|
|
func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
|
|
id := wr.StreamID()
|
|
if id == 0 {
|
|
ws.zero.push(wr)
|
|
return
|
|
}
|
|
q, ok := ws.sq[id]
|
|
if !ok {
|
|
q = ws.queuePool.get()
|
|
ws.sq[id] = q
|
|
}
|
|
q.push(wr)
|
|
}
|
|
|
|
func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
|
|
// Control frames first.
|
|
if !ws.zero.empty() {
|
|
return ws.zero.shift(), true
|
|
}
|
|
// Iterate over all non-idle streams until finding one that can be consumed.
|
|
for _, q := range ws.sq {
|
|
if wr, ok := q.consume(math.MaxInt32); ok {
|
|
return wr, true
|
|
}
|
|
}
|
|
return FrameWriteRequest{}, false
|
|
}
|