Home | History | Annotate | Download | only in http2
      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 }
     73