github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/Godeps/_workspace/src/google.golang.org/grpc/transport/control.go (about)

     1  /*
     2   *
     3   * Copyright 2014, Google Inc.
     4   * All rights reserved.
     5   *
     6   * Redistribution and use in source and binary forms, with or without
     7   * modification, are permitted provided that the following conditions are
     8   * met:
     9   *
    10   *     * Redistributions of source code must retain the above copyright
    11   * notice, this list of conditions and the following disclaimer.
    12   *     * Redistributions in binary form must reproduce the above
    13   * copyright notice, this list of conditions and the following disclaimer
    14   * in the documentation and/or other materials provided with the
    15   * distribution.
    16   *     * Neither the name of Google Inc. nor the names of its
    17   * contributors may be used to endorse or promote products derived from
    18   * this software without specific prior written permission.
    19   *
    20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31   *
    32   */
    33  
    34  package transport
    35  
    36  import (
    37  	"fmt"
    38  	"sync"
    39  
    40  	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/bradfitz/http2"
    41  )
    42  
    43  const (
    44  	// The default value of flow control window size in HTTP2 spec.
    45  	defaultWindowSize = 65535
    46  	// The initial window size for flow control.
    47  	initialWindowSize     = defaultWindowSize      // for an RPC
    48  	initialConnWindowSize = defaultWindowSize * 16 // for a connection
    49  )
    50  
    51  // The following defines various control items which could flow through
    52  // the control buffer of transport. They represent different aspects of
    53  // control tasks, e.g., flow control, settings, streaming resetting, etc.
    54  type windowUpdate struct {
    55  	streamID  uint32
    56  	increment uint32
    57  }
    58  
    59  func (windowUpdate) isItem() bool {
    60  	return true
    61  }
    62  
    63  type settings struct {
    64  	ack bool
    65  	ss  []http2.Setting
    66  }
    67  
    68  func (settings) isItem() bool {
    69  	return true
    70  }
    71  
    72  type resetStream struct {
    73  	streamID uint32
    74  	code     http2.ErrCode
    75  }
    76  
    77  func (resetStream) isItem() bool {
    78  	return true
    79  }
    80  
    81  type flushIO struct {
    82  }
    83  
    84  func (flushIO) isItem() bool {
    85  	return true
    86  }
    87  
    88  type ping struct {
    89  	ack bool
    90  }
    91  
    92  func (ping) isItem() bool {
    93  	return true
    94  }
    95  
    96  // quotaPool is a pool which accumulates the quota and sends it to acquire()
    97  // when it is available.
    98  type quotaPool struct {
    99  	c chan int
   100  
   101  	mu    sync.Mutex
   102  	quota int
   103  }
   104  
   105  // newQuotaPool creates a quotaPool which has quota q available to consume.
   106  func newQuotaPool(q int) *quotaPool {
   107  	qb := &quotaPool{
   108  		c: make(chan int, 1),
   109  	}
   110  	if q > 0 {
   111  		qb.c <- q
   112  	} else {
   113  		qb.quota = q
   114  	}
   115  	return qb
   116  }
   117  
   118  // add adds n to the available quota and tries to send it on acquire.
   119  func (qb *quotaPool) add(n int) {
   120  	qb.mu.Lock()
   121  	defer qb.mu.Unlock()
   122  	qb.quota += n
   123  	if qb.quota <= 0 {
   124  		return
   125  	}
   126  	select {
   127  	case qb.c <- qb.quota:
   128  		qb.quota = 0
   129  	default:
   130  	}
   131  }
   132  
   133  // cancel cancels the pending quota sent on acquire, if any.
   134  func (qb *quotaPool) cancel() {
   135  	qb.mu.Lock()
   136  	defer qb.mu.Unlock()
   137  	select {
   138  	case n := <-qb.c:
   139  		qb.quota += n
   140  	default:
   141  	}
   142  }
   143  
   144  // reset cancels the pending quota sent on acquired, incremented by v and sends
   145  // it back on acquire.
   146  func (qb *quotaPool) reset(v int) {
   147  	qb.mu.Lock()
   148  	defer qb.mu.Unlock()
   149  	select {
   150  	case n := <-qb.c:
   151  		qb.quota += n
   152  	default:
   153  	}
   154  	qb.quota += v
   155  	if qb.quota <= 0 {
   156  		return
   157  	}
   158  	select {
   159  	case qb.c <- qb.quota:
   160  		qb.quota = 0
   161  	default:
   162  	}
   163  }
   164  
   165  // acquire returns the channel on which available quota amounts are sent.
   166  func (qb *quotaPool) acquire() <-chan int {
   167  	return qb.c
   168  }
   169  
   170  // inFlow deals with inbound flow control
   171  type inFlow struct {
   172  	// The inbound flow control limit for pending data.
   173  	limit uint32
   174  	// conn points to the shared connection-level inFlow that is shared
   175  	// by all streams on that conn. It is nil for the inFlow on the conn
   176  	// directly.
   177  	conn *inFlow
   178  
   179  	mu sync.Mutex
   180  	// pendingData is the overall data which have been received but not been
   181  	// consumed by applications.
   182  	pendingData uint32
   183  	// The amount of data the application has consumed but grpc has not sent
   184  	// window update for them. Used to reduce window update frequency.
   185  	pendingUpdate uint32
   186  }
   187  
   188  // onData is invoked when some data frame is received. It increments not only its
   189  // own pendingData but also that of the associated connection-level flow.
   190  func (f *inFlow) onData(n uint32) error {
   191  	if n == 0 {
   192  		return nil
   193  	}
   194  	f.mu.Lock()
   195  	defer f.mu.Unlock()
   196  	if f.pendingData+f.pendingUpdate+n > f.limit {
   197  		return fmt.Errorf("recieved %d-bytes data exceeding the limit %d bytes", f.pendingData+f.pendingUpdate+n, f.limit)
   198  	}
   199  	if f.conn != nil {
   200  		if err := f.conn.onData(n); err != nil {
   201  			return ConnectionErrorf("%v", err)
   202  		}
   203  	}
   204  	f.pendingData += n
   205  	return nil
   206  }
   207  
   208  // connOnRead updates the connection level states when the application consumes data.
   209  func (f *inFlow) connOnRead(n uint32) uint32 {
   210  	if n == 0 || f.conn != nil {
   211  		return 0
   212  	}
   213  	f.mu.Lock()
   214  	defer f.mu.Unlock()
   215  	f.pendingData -= n
   216  	f.pendingUpdate += n
   217  	if f.pendingUpdate >= f.limit/4 {
   218  		ret := f.pendingUpdate
   219  		f.pendingUpdate = 0
   220  		return ret
   221  	}
   222  	return 0
   223  }
   224  
   225  // onRead is invoked when the application reads the data. It returns the window updates
   226  // for both stream and connection level.
   227  func (f *inFlow) onRead(n uint32) (swu, cwu uint32) {
   228  	if n == 0 {
   229  		return
   230  	}
   231  	f.mu.Lock()
   232  	defer f.mu.Unlock()
   233  	if f.pendingData == 0 {
   234  		// pendingData has been adjusted by restoreConn.
   235  		return
   236  	}
   237  	f.pendingData -= n
   238  	f.pendingUpdate += n
   239  	if f.pendingUpdate >= f.limit/4 {
   240  		swu = f.pendingUpdate
   241  		f.pendingUpdate = 0
   242  	}
   243  	cwu = f.conn.connOnRead(n)
   244  	return
   245  }
   246  
   247  // restoreConn is invoked when a stream is terminated. It removes its stake in
   248  // the connection-level flow and resets its own state.
   249  func (f *inFlow) restoreConn() uint32 {
   250  	if f.conn == nil {
   251  		return 0
   252  	}
   253  	f.mu.Lock()
   254  	defer f.mu.Unlock()
   255  	n := f.pendingData
   256  	f.pendingData = 0
   257  	f.pendingUpdate = 0
   258  	return f.conn.connOnRead(n)
   259  }