You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

219 lines
5.6 KiB

  1. /*
  2. *
  3. * Copyright 2014 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package transport
  19. import (
  20. "fmt"
  21. "math"
  22. "sync"
  23. "sync/atomic"
  24. )
  25. // writeQuota is a soft limit on the amount of data a stream can
  26. // schedule before some of it is written out.
  27. type writeQuota struct {
  28. quota int32
  29. // get waits on read from when quota goes less than or equal to zero.
  30. // replenish writes on it when quota goes positive again.
  31. ch chan struct{}
  32. // done is triggered in error case.
  33. done <-chan struct{}
  34. // replenish is called by loopyWriter to give quota back to.
  35. // It is implemented as a field so that it can be updated
  36. // by tests.
  37. replenish func(n int)
  38. }
  39. func newWriteQuota(sz int32, done <-chan struct{}) *writeQuota {
  40. w := &writeQuota{
  41. quota: sz,
  42. ch: make(chan struct{}, 1),
  43. done: done,
  44. }
  45. w.replenish = w.realReplenish
  46. return w
  47. }
  48. func (w *writeQuota) get(sz int32) error {
  49. for {
  50. if atomic.LoadInt32(&w.quota) > 0 {
  51. atomic.AddInt32(&w.quota, -sz)
  52. return nil
  53. }
  54. select {
  55. case <-w.ch:
  56. continue
  57. case <-w.done:
  58. return errStreamDone
  59. }
  60. }
  61. }
  62. func (w *writeQuota) realReplenish(n int) {
  63. sz := int32(n)
  64. a := atomic.AddInt32(&w.quota, sz)
  65. b := a - sz
  66. if b <= 0 && a > 0 {
  67. select {
  68. case w.ch <- struct{}{}:
  69. default:
  70. }
  71. }
  72. }
  73. type trInFlow struct {
  74. limit uint32
  75. unacked uint32
  76. effectiveWindowSize uint32
  77. }
  78. func (f *trInFlow) newLimit(n uint32) uint32 {
  79. d := n - f.limit
  80. f.limit = n
  81. f.updateEffectiveWindowSize()
  82. return d
  83. }
  84. func (f *trInFlow) onData(n uint32) uint32 {
  85. f.unacked += n
  86. if f.unacked >= f.limit/4 {
  87. w := f.unacked
  88. f.unacked = 0
  89. f.updateEffectiveWindowSize()
  90. return w
  91. }
  92. f.updateEffectiveWindowSize()
  93. return 0
  94. }
  95. func (f *trInFlow) reset() uint32 {
  96. w := f.unacked
  97. f.unacked = 0
  98. f.updateEffectiveWindowSize()
  99. return w
  100. }
  101. func (f *trInFlow) updateEffectiveWindowSize() {
  102. atomic.StoreUint32(&f.effectiveWindowSize, f.limit-f.unacked)
  103. }
  104. func (f *trInFlow) getSize() uint32 {
  105. return atomic.LoadUint32(&f.effectiveWindowSize)
  106. }
  107. // TODO(mmukhi): Simplify this code.
  108. // inFlow deals with inbound flow control
  109. type inFlow struct {
  110. mu sync.Mutex
  111. // The inbound flow control limit for pending data.
  112. limit uint32
  113. // pendingData is the overall data which have been received but not been
  114. // consumed by applications.
  115. pendingData uint32
  116. // The amount of data the application has consumed but grpc has not sent
  117. // window update for them. Used to reduce window update frequency.
  118. pendingUpdate uint32
  119. // delta is the extra window update given by receiver when an application
  120. // is reading data bigger in size than the inFlow limit.
  121. delta uint32
  122. }
  123. // newLimit updates the inflow window to a new value n.
  124. // It assumes that n is always greater than the old limit.
  125. func (f *inFlow) newLimit(n uint32) uint32 {
  126. f.mu.Lock()
  127. d := n - f.limit
  128. f.limit = n
  129. f.mu.Unlock()
  130. return d
  131. }
  132. func (f *inFlow) maybeAdjust(n uint32) uint32 {
  133. if n > uint32(math.MaxInt32) {
  134. n = uint32(math.MaxInt32)
  135. }
  136. f.mu.Lock()
  137. // estSenderQuota is the receiver's view of the maximum number of bytes the sender
  138. // can send without a window update.
  139. estSenderQuota := int32(f.limit - (f.pendingData + f.pendingUpdate))
  140. // estUntransmittedData is the maximum number of bytes the sends might not have put
  141. // on the wire yet. A value of 0 or less means that we have already received all or
  142. // more bytes than the application is requesting to read.
  143. estUntransmittedData := int32(n - f.pendingData) // Casting into int32 since it could be negative.
  144. // This implies that unless we send a window update, the sender won't be able to send all the bytes
  145. // for this message. Therefore we must send an update over the limit since there's an active read
  146. // request from the application.
  147. if estUntransmittedData > estSenderQuota {
  148. // Sender's window shouldn't go more than 2^31 - 1 as specified in the HTTP spec.
  149. if f.limit+n > maxWindowSize {
  150. f.delta = maxWindowSize - f.limit
  151. } else {
  152. // Send a window update for the whole message and not just the difference between
  153. // estUntransmittedData and estSenderQuota. This will be helpful in case the message
  154. // is padded; We will fallback on the current available window(at least a 1/4th of the limit).
  155. f.delta = n
  156. }
  157. f.mu.Unlock()
  158. return f.delta
  159. }
  160. f.mu.Unlock()
  161. return 0
  162. }
  163. // onData is invoked when some data frame is received. It updates pendingData.
  164. func (f *inFlow) onData(n uint32) error {
  165. f.mu.Lock()
  166. f.pendingData += n
  167. if f.pendingData+f.pendingUpdate > f.limit+f.delta {
  168. limit := f.limit
  169. rcvd := f.pendingData + f.pendingUpdate
  170. f.mu.Unlock()
  171. return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", rcvd, limit)
  172. }
  173. f.mu.Unlock()
  174. return nil
  175. }
  176. // onRead is invoked when the application reads the data. It returns the window size
  177. // to be sent to the peer.
  178. func (f *inFlow) onRead(n uint32) uint32 {
  179. f.mu.Lock()
  180. if f.pendingData == 0 {
  181. f.mu.Unlock()
  182. return 0
  183. }
  184. f.pendingData -= n
  185. if n > f.delta {
  186. n -= f.delta
  187. f.delta = 0
  188. } else {
  189. f.delta -= n
  190. n = 0
  191. }
  192. f.pendingUpdate += n
  193. if f.pendingUpdate >= f.limit/4 {
  194. wu := f.pendingUpdate
  195. f.pendingUpdate = 0
  196. f.mu.Unlock()
  197. return wu
  198. }
  199. f.mu.Unlock()
  200. return 0
  201. }