gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

flow.go (3370B)


      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 // Flow control
      6 
      7 package http2
      8 
      9 // inflowMinRefresh is the minimum number of bytes we'll send for a
     10 // flow control window update.
     11 const inflowMinRefresh = 4 << 10
     12 
     13 // inflow accounts for an inbound flow control window.
     14 // It tracks both the latest window sent to the peer (used for enforcement)
     15 // and the accumulated unsent window.
     16 type inflow struct {
     17 	avail  int32
     18 	unsent int32
     19 }
     20 
     21 // init sets the initial window.
     22 func (f *inflow) init(n int32) {
     23 	f.avail = n
     24 }
     25 
     26 // add adds n bytes to the window, with a maximum window size of max,
     27 // indicating that the peer can now send us more data.
     28 // For example, the user read from a {Request,Response} body and consumed
     29 // some of the buffered data, so the peer can now send more.
     30 // It returns the number of bytes to send in a WINDOW_UPDATE frame to the peer.
     31 // Window updates are accumulated and sent when the unsent capacity
     32 // is at least inflowMinRefresh or will at least double the peer's available window.
     33 func (f *inflow) add(n int) (connAdd int32) {
     34 	if n < 0 {
     35 		panic("negative update")
     36 	}
     37 	unsent := int64(f.unsent) + int64(n)
     38 	// "A sender MUST NOT allow a flow-control window to exceed 2^31-1 octets."
     39 	// RFC 7540 Section 6.9.1.
     40 	const maxWindow = 1<<31 - 1
     41 	if unsent+int64(f.avail) > maxWindow {
     42 		panic("flow control update exceeds maximum window size")
     43 	}
     44 	f.unsent = int32(unsent)
     45 	if f.unsent < inflowMinRefresh && f.unsent < f.avail {
     46 		// If there aren't at least inflowMinRefresh bytes of window to send,
     47 		// and this update won't at least double the window, buffer the update for later.
     48 		return 0
     49 	}
     50 	f.avail += f.unsent
     51 	f.unsent = 0
     52 	return int32(unsent)
     53 }
     54 
     55 // take attempts to take n bytes from the peer's flow control window.
     56 // It reports whether the window has available capacity.
     57 func (f *inflow) take(n uint32) bool {
     58 	if n > uint32(f.avail) {
     59 		return false
     60 	}
     61 	f.avail -= int32(n)
     62 	return true
     63 }
     64 
     65 // takeInflows attempts to take n bytes from two inflows,
     66 // typically connection-level and stream-level flows.
     67 // It reports whether both windows have available capacity.
     68 func takeInflows(f1, f2 *inflow, n uint32) bool {
     69 	if n > uint32(f1.avail) || n > uint32(f2.avail) {
     70 		return false
     71 	}
     72 	f1.avail -= int32(n)
     73 	f2.avail -= int32(n)
     74 	return true
     75 }
     76 
     77 // outflow is the outbound flow control window's size.
     78 type outflow struct {
     79 	_ incomparable
     80 
     81 	// n is the number of DATA bytes we're allowed to send.
     82 	// An outflow is kept both on a conn and a per-stream.
     83 	n int32
     84 
     85 	// conn points to the shared connection-level outflow that is
     86 	// shared by all streams on that conn. It is nil for the outflow
     87 	// that's on the conn directly.
     88 	conn *outflow
     89 }
     90 
     91 func (f *outflow) setConnFlow(cf *outflow) { f.conn = cf }
     92 
     93 func (f *outflow) available() int32 {
     94 	n := f.n
     95 	if f.conn != nil && f.conn.n < n {
     96 		n = f.conn.n
     97 	}
     98 	return n
     99 }
    100 
    101 func (f *outflow) take(n int32) {
    102 	if n > f.available() {
    103 		panic("internal error: took too much")
    104 	}
    105 	f.n -= n
    106 	if f.conn != nil {
    107 		f.conn.n -= n
    108 	}
    109 }
    110 
    111 // add adds n bytes (positive or negative) to the flow control window.
    112 // It returns false if the sum would exceed 2^31-1.
    113 func (f *outflow) add(n int32) bool {
    114 	sum := f.n + n
    115 	if (sum > n) == (f.n > 0) {
    116 		f.n = sum
    117 		return true
    118 	}
    119 	return false
    120 }