writesched.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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. package http2
  5. import "fmt"
  6. // WriteScheduler is the interface implemented by HTTP/2 write schedulers.
  7. // Methods are never called concurrently.
  8. type WriteScheduler interface {
  9. // OpenStream opens a new stream in the write scheduler.
  10. // It is illegal to call this with streamID=0 or with a streamID that is
  11. // already open -- the call may panic.
  12. OpenStream(streamID uint32, options OpenStreamOptions)
  13. // CloseStream closes a stream in the write scheduler. Any frames queued on
  14. // this stream should be discarded. It is illegal to call this on a stream
  15. // that is not open -- the call may panic.
  16. CloseStream(streamID uint32)
  17. // AdjustStream adjusts the priority of the given stream. This may be called
  18. // on a stream that has not yet been opened or has been closed. Note that
  19. // RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
  20. // https://tools.ietf.org/html/rfc7540#section-5.1
  21. AdjustStream(streamID uint32, priority PriorityParam)
  22. // Push queues a frame in the scheduler. In most cases, this will not be
  23. // called with wr.StreamID()!=0 unless that stream is currently open. The one
  24. // exception is RST_STREAM frames, which may be sent on idle or closed streams.
  25. Push(wr FrameWriteRequest)
  26. // Pop dequeues the next frame to write. Returns false if no frames can
  27. // be written. Frames with a given wr.StreamID() are Pop'd in the same
  28. // order they are Push'd, except RST_STREAM frames. No frames should be
  29. // discarded except by CloseStream.
  30. Pop() (wr FrameWriteRequest, ok bool)
  31. }
  32. // OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
  33. type OpenStreamOptions struct {
  34. // PusherID is zero if the stream was initiated by the client. Otherwise,
  35. // PusherID names the stream that pushed the newly opened stream.
  36. PusherID uint32
  37. // priority is used to set the priority of the newly opened stream.
  38. priority PriorityParam
  39. }
  40. // FrameWriteRequest is a request to write a frame.
  41. type FrameWriteRequest struct {
  42. // write is the interface value that does the writing, once the
  43. // WriteScheduler has selected this frame to write. The write
  44. // functions are all defined in write.go.
  45. write writeFramer
  46. // stream is the stream on which this frame will be written.
  47. // nil for non-stream frames like PING and SETTINGS.
  48. // nil for RST_STREAM streams, which use the StreamError.StreamID field instead.
  49. stream *stream
  50. // done, if non-nil, must be a buffered channel with space for
  51. // 1 message and is sent the return value from write (or an
  52. // earlier error) when the frame has been written.
  53. done chan error
  54. }
  55. // StreamID returns the id of the stream this frame will be written to.
  56. // 0 is used for non-stream frames such as PING and SETTINGS.
  57. func (wr FrameWriteRequest) StreamID() uint32 {
  58. if wr.stream == nil {
  59. if se, ok := wr.write.(StreamError); ok {
  60. // (*serverConn).resetStream doesn't set
  61. // stream because it doesn't necessarily have
  62. // one. So special case this type of write
  63. // message.
  64. return se.StreamID
  65. }
  66. return 0
  67. }
  68. return wr.stream.id
  69. }
  70. // isControl reports whether wr is a control frame for MaxQueuedControlFrames
  71. // purposes. That includes non-stream frames and RST_STREAM frames.
  72. func (wr FrameWriteRequest) isControl() bool {
  73. return wr.stream == nil
  74. }
  75. // DataSize returns the number of flow control bytes that must be consumed
  76. // to write this entire frame. This is 0 for non-DATA frames.
  77. func (wr FrameWriteRequest) DataSize() int {
  78. if wd, ok := wr.write.(*writeData); ok {
  79. return len(wd.p)
  80. }
  81. return 0
  82. }
  83. // Consume consumes min(n, available) bytes from this frame, where available
  84. // is the number of flow control bytes available on the stream. Consume returns
  85. // 0, 1, or 2 frames, where the integer return value gives the number of frames
  86. // returned.
  87. //
  88. // If flow control prevents consuming any bytes, this returns (_, _, 0). If
  89. // the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
  90. // returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
  91. // 'rest' contains the remaining bytes. The consumed bytes are deducted from the
  92. // underlying stream's flow control budget.
  93. func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
  94. var empty FrameWriteRequest
  95. // Non-DATA frames are always consumed whole.
  96. wd, ok := wr.write.(*writeData)
  97. if !ok || len(wd.p) == 0 {
  98. return wr, empty, 1
  99. }
  100. // Might need to split after applying limits.
  101. allowed := wr.stream.flow.available()
  102. if n < allowed {
  103. allowed = n
  104. }
  105. if wr.stream.sc.maxFrameSize < allowed {
  106. allowed = wr.stream.sc.maxFrameSize
  107. }
  108. if allowed <= 0 {
  109. return empty, empty, 0
  110. }
  111. if len(wd.p) > int(allowed) {
  112. wr.stream.flow.take(allowed)
  113. consumed := FrameWriteRequest{
  114. stream: wr.stream,
  115. write: &writeData{
  116. streamID: wd.streamID,
  117. p: wd.p[:allowed],
  118. // Even if the original had endStream set, there
  119. // are bytes remaining because len(wd.p) > allowed,
  120. // so we know endStream is false.
  121. endStream: false,
  122. },
  123. // Our caller is blocking on the final DATA frame, not
  124. // this intermediate frame, so no need to wait.
  125. done: nil,
  126. }
  127. rest := FrameWriteRequest{
  128. stream: wr.stream,
  129. write: &writeData{
  130. streamID: wd.streamID,
  131. p: wd.p[allowed:],
  132. endStream: wd.endStream,
  133. },
  134. done: wr.done,
  135. }
  136. return consumed, rest, 2
  137. }
  138. // The frame is consumed whole.
  139. // NB: This cast cannot overflow because allowed is <= math.MaxInt32.
  140. wr.stream.flow.take(int32(len(wd.p)))
  141. return wr, empty, 1
  142. }
  143. // String is for debugging only.
  144. func (wr FrameWriteRequest) String() string {
  145. var des string
  146. if s, ok := wr.write.(fmt.Stringer); ok {
  147. des = s.String()
  148. } else {
  149. des = fmt.Sprintf("%T", wr.write)
  150. }
  151. return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
  152. }
  153. // replyToWriter sends err to wr.done and panics if the send must block
  154. // This does nothing if wr.done is nil.
  155. func (wr *FrameWriteRequest) replyToWriter(err error) {
  156. if wr.done == nil {
  157. return
  158. }
  159. select {
  160. case wr.done <- err:
  161. default:
  162. panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
  163. }
  164. wr.write = nil // prevent use (assume it's tainted after wr.done send)
  165. }
  166. // writeQueue is used by implementations of WriteScheduler.
  167. //
  168. // Each writeQueue contains a queue of FrameWriteRequests, meant to store all
  169. // FrameWriteRequests associated with a given stream. This is implemented as a
  170. // two-stage queue: currQueue[currPos:] and nextQueue. Removing an item is done
  171. // by incrementing currPos of currQueue. Adding an item is done by appending it
  172. // to the nextQueue. If currQueue is empty when trying to remove an item, we
  173. // can swap currQueue and nextQueue to remedy the situation.
  174. // This two-stage queue is analogous to the use of two lists in Okasaki's
  175. // purely functional queue but without the overhead of reversing the list when
  176. // swapping stages.
  177. //
  178. // writeQueue also contains prev and next, this can be used by implementations
  179. // of WriteScheduler to construct data structures that represent the order of
  180. // writing between different streams (e.g. circular linked list).
  181. type writeQueue struct {
  182. currQueue []FrameWriteRequest
  183. nextQueue []FrameWriteRequest
  184. currPos int
  185. prev, next *writeQueue
  186. }
  187. func (q *writeQueue) empty() bool {
  188. return (len(q.currQueue) - q.currPos + len(q.nextQueue)) == 0
  189. }
  190. func (q *writeQueue) push(wr FrameWriteRequest) {
  191. q.nextQueue = append(q.nextQueue, wr)
  192. }
  193. func (q *writeQueue) shift() FrameWriteRequest {
  194. if q.empty() {
  195. panic("invalid use of queue")
  196. }
  197. if q.currPos >= len(q.currQueue) {
  198. q.currQueue, q.currPos, q.nextQueue = q.nextQueue, 0, q.currQueue[:0]
  199. }
  200. wr := q.currQueue[q.currPos]
  201. q.currQueue[q.currPos] = FrameWriteRequest{}
  202. q.currPos++
  203. return wr
  204. }
  205. func (q *writeQueue) peek() *FrameWriteRequest {
  206. if q.currPos < len(q.currQueue) {
  207. return &q.currQueue[q.currPos]
  208. }
  209. if len(q.nextQueue) > 0 {
  210. return &q.nextQueue[0]
  211. }
  212. return nil
  213. }
  214. // consume consumes up to n bytes from q.s[0]. If the frame is
  215. // entirely consumed, it is removed from the queue. If the frame
  216. // is partially consumed, the frame is kept with the consumed
  217. // bytes removed. Returns true iff any bytes were consumed.
  218. func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
  219. if q.empty() {
  220. return FrameWriteRequest{}, false
  221. }
  222. consumed, rest, numresult := q.peek().Consume(n)
  223. switch numresult {
  224. case 0:
  225. return FrameWriteRequest{}, false
  226. case 1:
  227. q.shift()
  228. case 2:
  229. *q.peek() = rest
  230. }
  231. return consumed, true
  232. }
  233. type writeQueuePool []*writeQueue
  234. // put inserts an unused writeQueue into the pool.
  235. func (p *writeQueuePool) put(q *writeQueue) {
  236. for i := range q.currQueue {
  237. q.currQueue[i] = FrameWriteRequest{}
  238. }
  239. for i := range q.nextQueue {
  240. q.nextQueue[i] = FrameWriteRequest{}
  241. }
  242. q.currQueue = q.currQueue[:0]
  243. q.nextQueue = q.nextQueue[:0]
  244. q.currPos = 0
  245. *p = append(*p, q)
  246. }
  247. // get returns an empty writeQueue.
  248. func (p *writeQueuePool) get() *writeQueue {
  249. ln := len(*p)
  250. if ln == 0 {
  251. return new(writeQueue)
  252. }
  253. x := ln - 1
  254. q := (*p)[x]
  255. (*p)[x] = nil
  256. *p = (*p)[:x]
  257. return q
  258. }