writesched.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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.
  23. Push(wr FrameWriteRequest)
  24. // Pop dequeues the next frame to write. Returns false if no frames can
  25. // be written. Frames with a given wr.StreamID() are Pop'd in the same
  26. // order they are Push'd.
  27. Pop() (wr FrameWriteRequest, ok bool)
  28. }
  29. // OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
  30. type OpenStreamOptions struct {
  31. // PusherID is zero if the stream was initiated by the client. Otherwise,
  32. // PusherID names the stream that pushed the newly opened stream.
  33. PusherID uint32
  34. }
  35. // FrameWriteRequest is a request to write a frame.
  36. type FrameWriteRequest struct {
  37. // write is the interface value that does the writing, once the
  38. // WriteScheduler has selected this frame to write. The write
  39. // functions are all defined in write.go.
  40. write writeFramer
  41. // stream is the stream on which this frame will be written.
  42. // nil for non-stream frames like PING and SETTINGS.
  43. stream *stream
  44. // done, if non-nil, must be a buffered channel with space for
  45. // 1 message and is sent the return value from write (or an
  46. // earlier error) when the frame has been written.
  47. done chan error
  48. }
  49. // StreamID returns the id of the stream this frame will be written to.
  50. // 0 is used for non-stream frames such as PING and SETTINGS.
  51. func (wr FrameWriteRequest) StreamID() uint32 {
  52. if wr.stream == nil {
  53. if se, ok := wr.write.(StreamError); ok {
  54. // (*serverConn).resetStream doesn't set
  55. // stream because it doesn't necessarily have
  56. // one. So special case this type of write
  57. // message.
  58. return se.StreamID
  59. }
  60. return 0
  61. }
  62. return wr.stream.id
  63. }
  64. // DataSize returns the number of flow control bytes that must be consumed
  65. // to write this entire frame. This is 0 for non-DATA frames.
  66. func (wr FrameWriteRequest) DataSize() int {
  67. if wd, ok := wr.write.(*writeData); ok {
  68. return len(wd.p)
  69. }
  70. return 0
  71. }
  72. // Consume consumes min(n, available) bytes from this frame, where available
  73. // is the number of flow control bytes available on the stream. Consume returns
  74. // 0, 1, or 2 frames, where the integer return value gives the number of frames
  75. // returned.
  76. //
  77. // If flow control prevents consuming any bytes, this returns (_, _, 0). If
  78. // the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
  79. // returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
  80. // 'rest' contains the remaining bytes. The consumed bytes are deducted from the
  81. // underlying stream's flow control budget.
  82. func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
  83. var empty FrameWriteRequest
  84. // Non-DATA frames are always consumed whole.
  85. wd, ok := wr.write.(*writeData)
  86. if !ok || len(wd.p) == 0 {
  87. return wr, empty, 1
  88. }
  89. // Might need to split after applying limits.
  90. allowed := wr.stream.flow.available()
  91. if n < allowed {
  92. allowed = n
  93. }
  94. if wr.stream.sc.maxFrameSize < allowed {
  95. allowed = wr.stream.sc.maxFrameSize
  96. }
  97. if allowed <= 0 {
  98. return empty, empty, 0
  99. }
  100. if len(wd.p) > int(allowed) {
  101. wr.stream.flow.take(allowed)
  102. consumed := FrameWriteRequest{
  103. stream: wr.stream,
  104. write: &writeData{
  105. streamID: wd.streamID,
  106. p: wd.p[:allowed],
  107. // Even if the original had endStream set, there
  108. // are bytes remaining because len(wd.p) > allowed,
  109. // so we know endStream is false.
  110. endStream: false,
  111. },
  112. // Our caller is blocking on the final DATA frame, not
  113. // this intermediate frame, so no need to wait.
  114. done: nil,
  115. }
  116. rest := FrameWriteRequest{
  117. stream: wr.stream,
  118. write: &writeData{
  119. streamID: wd.streamID,
  120. p: wd.p[allowed:],
  121. endStream: wd.endStream,
  122. },
  123. done: wr.done,
  124. }
  125. return consumed, rest, 2
  126. }
  127. // The frame is consumed whole.
  128. // NB: This cast cannot overflow because allowed is <= math.MaxInt32.
  129. wr.stream.flow.take(int32(len(wd.p)))
  130. return wr, empty, 1
  131. }
  132. // String is for debugging only.
  133. func (wr FrameWriteRequest) String() string {
  134. var des string
  135. if s, ok := wr.write.(fmt.Stringer); ok {
  136. des = s.String()
  137. } else {
  138. des = fmt.Sprintf("%T", wr.write)
  139. }
  140. return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
  141. }
  142. // writeQueue is used by implementations of WriteScheduler.
  143. type writeQueue struct {
  144. s []FrameWriteRequest
  145. }
  146. func (q *writeQueue) empty() bool { return len(q.s) == 0 }
  147. func (q *writeQueue) push(wr FrameWriteRequest) {
  148. q.s = append(q.s, wr)
  149. }
  150. func (q *writeQueue) shift() FrameWriteRequest {
  151. if len(q.s) == 0 {
  152. panic("invalid use of queue")
  153. }
  154. wr := q.s[0]
  155. // TODO: less copy-happy queue.
  156. copy(q.s, q.s[1:])
  157. q.s[len(q.s)-1] = FrameWriteRequest{}
  158. q.s = q.s[:len(q.s)-1]
  159. return wr
  160. }
  161. // consume consumes up to n bytes from q.s[0]. If the frame is
  162. // entirely consumed, it is removed from the queue. If the frame
  163. // is partially consumed, the frame is kept with the consumed
  164. // bytes removed. Returns true iff any bytes were consumed.
  165. func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
  166. if len(q.s) == 0 {
  167. return FrameWriteRequest{}, false
  168. }
  169. consumed, rest, numresult := q.s[0].Consume(n)
  170. switch numresult {
  171. case 0:
  172. return FrameWriteRequest{}, false
  173. case 1:
  174. q.shift()
  175. case 2:
  176. q.s[0] = rest
  177. }
  178. return consumed, true
  179. }
  180. type writeQueuePool []*writeQueue
  181. // put inserts an unused writeQueue into the pool.
  182. func (p *writeQueuePool) put(q *writeQueue) {
  183. for i := range q.s {
  184. q.s[i] = FrameWriteRequest{}
  185. }
  186. q.s = q.s[:0]
  187. *p = append(*p, q)
  188. }
  189. // get returns an empty writeQueue.
  190. func (p *writeQueuePool) get() *writeQueue {
  191. ln := len(*p)
  192. if ln == 0 {
  193. return new(writeQueue)
  194. }
  195. x := ln - 1
  196. q := (*p)[x]
  197. (*p)[x] = nil
  198. *p = (*p)[:x]
  199. return q
  200. }