github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/http2/writesched_random.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http2
     6  
     7  import "math"
     8  
     9  // NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
    10  // priorities. Control frames like SETTINGS and PING are written before DATA
    11  // frames, but if no control frames are queued and multiple streams have queued
    12  // HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
    13  func NewRandomWriteScheduler() WriteScheduler {
    14  	return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
    15  }
    16  
    17  type randomWriteScheduler struct {
    18  	// zero are frames not associated with a specific stream.
    19  	zero writeQueue
    20  
    21  	// sq contains the stream-specific queues, keyed by stream ID.
    22  	// When a stream is idle or closed, it's deleted from the map.
    23  	sq map[uint32]*writeQueue
    24  
    25  	// pool of empty queues for reuse.
    26  	queuePool writeQueuePool
    27  }
    28  
    29  func (ws *randomWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
    30  	// no-op: idle streams are not tracked
    31  }
    32  
    33  func (ws *randomWriteScheduler) CloseStream(streamID uint32) {
    34  	q, ok := ws.sq[streamID]
    35  	if !ok {
    36  		return
    37  	}
    38  	delete(ws.sq, streamID)
    39  	ws.queuePool.put(q)
    40  }
    41  
    42  func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
    43  	// no-op: priorities are ignored
    44  }
    45  
    46  func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
    47  	id := wr.StreamID()
    48  	if id == 0 {
    49  		ws.zero.push(wr)
    50  		return
    51  	}
    52  	q, ok := ws.sq[id]
    53  	if !ok {
    54  		q = ws.queuePool.get()
    55  		ws.sq[id] = q
    56  	}
    57  	q.push(wr)
    58  }
    59  
    60  func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
    61  	// Control frames first.
    62  	if !ws.zero.empty() {
    63  		return ws.zero.shift(), true
    64  	}
    65  	// Iterate over all non-idle streams until finding one that can be consumed.
    66  	for _, q := range ws.sq {
    67  		if wr, ok := q.consume(math.MaxInt32); ok {
    68  			return wr, true
    69  		}
    70  	}
    71  	return FrameWriteRequest{}, false
    72  }