mirror of https://github.com/grpc/grpc-go.git
				
				
				
			client: Fix race when using both client-side default CallOptions and per-call CallOptions (#1948)
This commit is contained in:
		
							parent
							
								
									f72b28a6d1
								
							
						
					
					
						commit
						1a70180f35
					
				
							
								
								
									
										17
									
								
								call.go
								
								
								
								
							
							
						
						
									
										17
									
								
								call.go
								
								
								
								
							|  | @ -29,7 +29,7 @@ import ( | |||
| func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error { | ||||
| 	// allow interceptor to see all applicable call options, which means those
 | ||||
| 	// configured as defaults from dial option as well as per-call options
 | ||||
| 	opts = append(cc.dopts.callOptions, opts...) | ||||
| 	opts = combine(cc.dopts.callOptions, opts) | ||||
| 
 | ||||
| 	if cc.dopts.unaryInt != nil { | ||||
| 		return cc.dopts.unaryInt(ctx, method, args, reply, cc, invoke, opts...) | ||||
|  | @ -37,6 +37,21 @@ func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply int | |||
| 	return invoke(ctx, method, args, reply, cc, opts...) | ||||
| } | ||||
| 
 | ||||
| func combine(o1 []CallOption, o2 []CallOption) []CallOption { | ||||
| 	// we don't use append because o1 could have extra capacity whose
 | ||||
| 	// elements would be overwritten, which could cause inadvertent
 | ||||
| 	// sharing (and race connditions) between concurrent calls
 | ||||
| 	if len(o1) == 0 { | ||||
| 		return o2 | ||||
| 	} else if len(o2) == 0 { | ||||
| 		return o1 | ||||
| 	} | ||||
| 	ret := make([]CallOption, len(o1)+len(o2)) | ||||
| 	copy(ret, o1) | ||||
| 	copy(ret[len(o1):], o2) | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| // Invoke sends the RPC request on the wire and returns after response is
 | ||||
| // received.  This is typically called by generated code.
 | ||||
| //
 | ||||
|  |  | |||
|  | @ -104,7 +104,7 @@ type ClientStream interface { | |||
| func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { | ||||
| 	// allow interceptor to see all applicable call options, which means those
 | ||||
| 	// configured as defaults from dial option as well as per-call options
 | ||||
| 	opts = append(cc.dopts.callOptions, opts...) | ||||
| 	opts = combine(cc.dopts.callOptions, opts) | ||||
| 
 | ||||
| 	if cc.dopts.streamInt != nil { | ||||
| 		return cc.dopts.streamInt(ctx, desc, cc, method, newClientStream, opts...) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue