github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/Godeps/_workspace/src/google.golang.org/grpc/call.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 grpc
    35  
    36  import (
    37  	"io"
    38  	"time"
    39  
    40  	"golang.org/x/net/context"
    41  	"golang.org/x/net/trace"
    42  	"google.golang.org/grpc/codes"
    43  	"google.golang.org/grpc/transport"
    44  )
    45  
    46  // recvResponse receives and parses an RPC response.
    47  // On error, it returns the error and indicates whether the call should be retried.
    48  //
    49  // TODO(zhaoq): Check whether the received message sequence is valid.
    50  func recvResponse(codec Codec, t transport.ClientTransport, c *callInfo, stream *transport.Stream, reply interface{}) error {
    51  	// Try to acquire header metadata from the server if there is any.
    52  	var err error
    53  	c.headerMD, err = stream.Header()
    54  	if err != nil {
    55  		return err
    56  	}
    57  	p := &parser{s: stream}
    58  	for {
    59  		if err = recv(p, codec, reply); err != nil {
    60  			if err == io.EOF {
    61  				break
    62  			}
    63  			return err
    64  		}
    65  	}
    66  	c.trailerMD = stream.Trailer()
    67  	return nil
    68  }
    69  
    70  // sendRequest writes out various information of an RPC such as Context and Message.
    71  func sendRequest(ctx context.Context, codec Codec, callHdr *transport.CallHdr, t transport.ClientTransport, args interface{}, opts *transport.Options) (_ *transport.Stream, err error) {
    72  	stream, err := t.NewStream(ctx, callHdr)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	defer func() {
    77  		if err != nil {
    78  			if _, ok := err.(transport.ConnectionError); !ok {
    79  				t.CloseStream(stream, err)
    80  			}
    81  		}
    82  	}()
    83  	// TODO(zhaoq): Support compression.
    84  	outBuf, err := encode(codec, args, compressionNone)
    85  	if err != nil {
    86  		return nil, transport.StreamErrorf(codes.Internal, "grpc: %v", err)
    87  	}
    88  	err = t.Write(stream, outBuf, opts)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	// Sent successfully.
    93  	return stream, nil
    94  }
    95  
    96  // Invoke is called by the generated code. It sends the RPC request on the
    97  // wire and returns after response is received.
    98  func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) (err error) {
    99  	var c callInfo
   100  	for _, o := range opts {
   101  		if err := o.before(&c); err != nil {
   102  			return toRPCErr(err)
   103  		}
   104  	}
   105  	defer func() {
   106  		for _, o := range opts {
   107  			o.after(&c)
   108  		}
   109  	}()
   110  	if EnableTracing {
   111  		c.traceInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method)
   112  		defer c.traceInfo.tr.Finish()
   113  		c.traceInfo.firstLine.client = true
   114  		if deadline, ok := ctx.Deadline(); ok {
   115  			c.traceInfo.firstLine.deadline = deadline.Sub(time.Now())
   116  		}
   117  		c.traceInfo.tr.LazyLog(&c.traceInfo.firstLine, false)
   118  		// TODO(dsymonds): Arrange for c.traceInfo.firstLine.remoteAddr to be set.
   119  		defer func() {
   120  			if err != nil {
   121  				c.traceInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
   122  				c.traceInfo.tr.SetError()
   123  			}
   124  		}()
   125  	}
   126  	topts := &transport.Options{
   127  		Last:  true,
   128  		Delay: false,
   129  	}
   130  	var (
   131  		lastErr error // record the error that happened
   132  	)
   133  	for {
   134  		var (
   135  			err    error
   136  			t      transport.ClientTransport
   137  			stream *transport.Stream
   138  		)
   139  		// TODO(zhaoq): Need a formal spec of retry strategy for non-failfast rpcs.
   140  		if lastErr != nil && c.failFast {
   141  			return toRPCErr(lastErr)
   142  		}
   143  		callHdr := &transport.CallHdr{
   144  			Host:   cc.authority,
   145  			Method: method,
   146  		}
   147  		t, err = cc.dopts.picker.Pick(ctx)
   148  		if err != nil {
   149  			if lastErr != nil {
   150  				// This was a retry; return the error from the last attempt.
   151  				return toRPCErr(lastErr)
   152  			}
   153  			return toRPCErr(err)
   154  		}
   155  		if c.traceInfo.tr != nil {
   156  			c.traceInfo.tr.LazyLog(&payload{sent: true, msg: args}, true)
   157  		}
   158  		stream, err = sendRequest(ctx, cc.dopts.codec, callHdr, t, args, topts)
   159  		if err != nil {
   160  			if _, ok := err.(transport.ConnectionError); ok {
   161  				lastErr = err
   162  				continue
   163  			}
   164  			if lastErr != nil {
   165  				return toRPCErr(lastErr)
   166  			}
   167  			return toRPCErr(err)
   168  		}
   169  		// Receive the response
   170  		lastErr = recvResponse(cc.dopts.codec, t, &c, stream, reply)
   171  		if _, ok := lastErr.(transport.ConnectionError); ok {
   172  			continue
   173  		}
   174  		if c.traceInfo.tr != nil {
   175  			c.traceInfo.tr.LazyLog(&payload{sent: false, msg: reply}, true)
   176  		}
   177  		t.CloseStream(stream, lastErr)
   178  		if lastErr != nil {
   179  			return toRPCErr(lastErr)
   180  		}
   181  		return Errorf(stream.StatusCode(), stream.StatusDesc())
   182  	}
   183  }