github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/Godeps/_workspace/src/golang.org/x/net/http2/writesched.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 // See https://code.google.com/p/go/source/browse/CONTRIBUTORS 5 // Licensed under the same terms as Go itself: 6 // https://code.google.com/p/go/source/browse/LICENSE 7 8 package http2 9 10 import "fmt" 11 12 // frameWriteMsg is a request to write a frame. 13 type frameWriteMsg struct { 14 // write is the interface value that does the writing, once the 15 // writeScheduler (below) has decided to select this frame 16 // to write. The write functions are all defined in write.go. 17 write writeFramer 18 19 stream *stream // used for prioritization. nil for non-stream frames. 20 21 // done, if non-nil, must be a buffered channel with space for 22 // 1 message and is sent the return value from write (or an 23 // earlier error) when the frame has been written. 24 done chan error 25 } 26 27 // for debugging only: 28 func (wm frameWriteMsg) String() string { 29 var streamID uint32 30 if wm.stream != nil { 31 streamID = wm.stream.id 32 } 33 var des string 34 if s, ok := wm.write.(fmt.Stringer); ok { 35 des = s.String() 36 } else { 37 des = fmt.Sprintf("%T", wm.write) 38 } 39 return fmt.Sprintf("[frameWriteMsg stream=%d, ch=%v, type: %v]", streamID, wm.done != nil, des) 40 } 41 42 // writeScheduler tracks pending frames to write, priorities, and decides 43 // the next one to use. It is not thread-safe. 44 type writeScheduler struct { 45 // zero are frames not associated with a specific stream. 46 // They're sent before any stream-specific freams. 47 zero writeQueue 48 49 // maxFrameSize is the maximum size of a DATA frame 50 // we'll write. Must be non-zero and between 16K-16M. 51 maxFrameSize uint32 52 53 // sq contains the stream-specific queues, keyed by stream ID. 54 // when a stream is idle, it's deleted from the map. 55 sq map[uint32]*writeQueue 56 57 // canSend is a slice of memory that's reused between frame 58 // scheduling decisions to hold the list of writeQueues (from sq) 59 // which have enough flow control data to send. After canSend is 60 // built, the best is selected. 61 canSend []*writeQueue 62 63 // pool of empty queues for reuse. 64 queuePool []*writeQueue 65 } 66 67 func (ws *writeScheduler) putEmptyQueue(q *writeQueue) { 68 if len(q.s) != 0 { 69 panic("queue must be empty") 70 } 71 ws.queuePool = append(ws.queuePool, q) 72 } 73 74 func (ws *writeScheduler) getEmptyQueue() *writeQueue { 75 ln := len(ws.queuePool) 76 if ln == 0 { 77 return new(writeQueue) 78 } 79 q := ws.queuePool[ln-1] 80 ws.queuePool = ws.queuePool[:ln-1] 81 return q 82 } 83 84 func (ws *writeScheduler) empty() bool { return ws.zero.empty() && len(ws.sq) == 0 } 85 86 func (ws *writeScheduler) add(wm frameWriteMsg) { 87 st := wm.stream 88 if st == nil { 89 ws.zero.push(wm) 90 } else { 91 ws.streamQueue(st.id).push(wm) 92 } 93 } 94 95 func (ws *writeScheduler) streamQueue(streamID uint32) *writeQueue { 96 if q, ok := ws.sq[streamID]; ok { 97 return q 98 } 99 if ws.sq == nil { 100 ws.sq = make(map[uint32]*writeQueue) 101 } 102 q := ws.getEmptyQueue() 103 ws.sq[streamID] = q 104 return q 105 } 106 107 // take returns the most important frame to write and removes it from the scheduler. 108 // It is illegal to call this if the scheduler is empty or if there are no connection-level 109 // flow control bytes available. 110 func (ws *writeScheduler) take() (wm frameWriteMsg, ok bool) { 111 if ws.maxFrameSize == 0 { 112 panic("internal error: ws.maxFrameSize not initialized or invalid") 113 } 114 115 // If there any frames not associated with streams, prefer those first. 116 // These are usually SETTINGS, etc. 117 if !ws.zero.empty() { 118 return ws.zero.shift(), true 119 } 120 if len(ws.sq) == 0 { 121 return 122 } 123 124 // Next, prioritize frames on streams that aren't DATA frames (no cost). 125 for id, q := range ws.sq { 126 if q.firstIsNoCost() { 127 return ws.takeFrom(id, q) 128 } 129 } 130 131 // Now, all that remains are DATA frames with non-zero bytes to 132 // send. So pick the best one. 133 if len(ws.canSend) != 0 { 134 panic("should be empty") 135 } 136 for _, q := range ws.sq { 137 if n := ws.streamWritableBytes(q); n > 0 { 138 ws.canSend = append(ws.canSend, q) 139 } 140 } 141 if len(ws.canSend) == 0 { 142 return 143 } 144 defer ws.zeroCanSend() 145 146 // TODO: find the best queue 147 q := ws.canSend[0] 148 149 return ws.takeFrom(q.streamID(), q) 150 } 151 152 // zeroCanSend is defered from take. 153 func (ws *writeScheduler) zeroCanSend() { 154 for i := range ws.canSend { 155 ws.canSend[i] = nil 156 } 157 ws.canSend = ws.canSend[:0] 158 } 159 160 // streamWritableBytes returns the number of DATA bytes we could write 161 // from the given queue's stream, if this stream/queue were 162 // selected. It is an error to call this if q's head isn't a 163 // *writeData. 164 func (ws *writeScheduler) streamWritableBytes(q *writeQueue) int32 { 165 wm := q.head() 166 ret := wm.stream.flow.available() // max we can write 167 if ret == 0 { 168 return 0 169 } 170 if int32(ws.maxFrameSize) < ret { 171 ret = int32(ws.maxFrameSize) 172 } 173 if ret == 0 { 174 panic("internal error: ws.maxFrameSize not initialized or invalid") 175 } 176 wd := wm.write.(*writeData) 177 if len(wd.p) < int(ret) { 178 ret = int32(len(wd.p)) 179 } 180 return ret 181 } 182 183 func (ws *writeScheduler) takeFrom(id uint32, q *writeQueue) (wm frameWriteMsg, ok bool) { 184 wm = q.head() 185 // If the first item in this queue costs flow control tokens 186 // and we don't have enough, write as much as we can. 187 if wd, ok := wm.write.(*writeData); ok && len(wd.p) > 0 { 188 allowed := wm.stream.flow.available() // max we can write 189 if allowed == 0 { 190 // No quota available. Caller can try the next stream. 191 return frameWriteMsg{}, false 192 } 193 if int32(ws.maxFrameSize) < allowed { 194 allowed = int32(ws.maxFrameSize) 195 } 196 // TODO: further restrict the allowed size, because even if 197 // the peer says it's okay to write 16MB data frames, we might 198 // want to write smaller ones to properly weight competing 199 // streams' priorities. 200 201 if len(wd.p) > int(allowed) { 202 wm.stream.flow.take(allowed) 203 chunk := wd.p[:allowed] 204 wd.p = wd.p[allowed:] 205 // Make up a new write message of a valid size, rather 206 // than shifting one off the queue. 207 return frameWriteMsg{ 208 stream: wm.stream, 209 write: &writeData{ 210 streamID: wd.streamID, 211 p: chunk, 212 // even if the original had endStream set, there 213 // arebytes remaining because len(wd.p) > allowed, 214 // so we know endStream is false: 215 endStream: false, 216 }, 217 // our caller is blocking on the final DATA frame, not 218 // these intermediates, so no need to wait: 219 done: nil, 220 }, true 221 } 222 wm.stream.flow.take(int32(len(wd.p))) 223 } 224 225 q.shift() 226 if q.empty() { 227 ws.putEmptyQueue(q) 228 delete(ws.sq, id) 229 } 230 return wm, true 231 } 232 233 func (ws *writeScheduler) forgetStream(id uint32) { 234 q, ok := ws.sq[id] 235 if !ok { 236 return 237 } 238 delete(ws.sq, id) 239 240 // But keep it for others later. 241 for i := range q.s { 242 q.s[i] = frameWriteMsg{} 243 } 244 q.s = q.s[:0] 245 ws.putEmptyQueue(q) 246 } 247 248 type writeQueue struct { 249 s []frameWriteMsg 250 } 251 252 // streamID returns the stream ID for a non-empty stream-specific queue. 253 func (q *writeQueue) streamID() uint32 { return q.s[0].stream.id } 254 255 func (q *writeQueue) empty() bool { return len(q.s) == 0 } 256 257 func (q *writeQueue) push(wm frameWriteMsg) { 258 q.s = append(q.s, wm) 259 } 260 261 // head returns the next item that would be removed by shift. 262 func (q *writeQueue) head() frameWriteMsg { 263 if len(q.s) == 0 { 264 panic("invalid use of queue") 265 } 266 return q.s[0] 267 } 268 269 func (q *writeQueue) shift() frameWriteMsg { 270 if len(q.s) == 0 { 271 panic("invalid use of queue") 272 } 273 wm := q.s[0] 274 // TODO: less copy-happy queue. 275 copy(q.s, q.s[1:]) 276 q.s[len(q.s)-1] = frameWriteMsg{} 277 q.s = q.s[:len(q.s)-1] 278 return wm 279 } 280 281 func (q *writeQueue) firstIsNoCost() bool { 282 if df, ok := q.s[0].write.(*writeData); ok { 283 return len(df.p) == 0 284 } 285 return true 286 }