balancer: add trailer metadata to DoneInfo (#2359)

This commit is contained in:
Doug Fawley 2018-10-10 13:21:08 -07:00 committed by GitHub
parent 55cdff2adc
commit c195587d96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 5 deletions

View File

@ -28,6 +28,7 @@ import (
"golang.org/x/net/context"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/resolver"
)
@ -160,6 +161,8 @@ type PickOptions struct {
type DoneInfo struct {
// Err is the rpc error the RPC finished with. It could be nil.
Err error
// Trailer contains the metadata from the RPC's trailer, if present.
Trailer metadata.MD
// BytesSent indicates if any bytes have been sent to the server.
BytesSent bool
// BytesReceived indicates if any byte has been received from the server.

View File

@ -682,7 +682,9 @@ func (t *http2Client) CloseStream(s *Stream, err error) {
func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.ErrCode, st *status.Status, mdata map[string][]string, eosReceived bool) {
// Set stream status to done.
if s.swapState(streamDone) == streamDone {
// If it was already done, return.
// If it was already done, return. If multiple closeStream calls
// happen simultaneously, wait for the first to finish.
<-s.done
return
}
// status and trailers can be updated here without any synchronization because the stream goroutine will
@ -696,8 +698,6 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.
// This will unblock reads eventually.
s.write(recvMsg{err: err})
}
// This will unblock write.
close(s.done)
// If headerChan isn't closed, then close it.
if atomic.SwapUint32(&s.headerDone, 1) == 0 {
s.noHeaders = true
@ -733,6 +733,8 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.
return true
}
t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
// This will unblock write.
close(s.done)
}
// Close kicks off the shutdown process of the transport. This should be called

View File

@ -816,11 +816,14 @@ func (a *csAttempt) finish(err error) {
if a.done != nil {
br := false
var tr metadata.MD
if a.s != nil {
br = a.s.BytesReceived()
tr = a.s.Trailer()
}
a.done(balancer.DoneInfo{
Err: err,
Trailer: tr,
BytesSent: a.s != nil,
BytesReceived: br,
})

View File

@ -152,7 +152,7 @@ func testDoneInfo(t *testing.T, e env) {
grpc.WithBalancerName(testBalancerName),
}
te.userAgent = failAppUA
te.startServer(&testServer{security: e.security, unaryCallSleepTime: time.Second})
te.startServer(&testServer{security: e.security})
defer te.tearDown()
cc := te.clientConn()
@ -164,7 +164,14 @@ func testDoneInfo(t *testing.T, e env) {
if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, %v", err, wantErr)
}
if len(b.doneInfo) != 1 || !reflect.DeepEqual(b.doneInfo[0].Err, wantErr) {
if _, err := tc.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil {
t.Fatalf("TestService.UnaryCall(%v, _, _, _) = _, %v; want _, <nil>", ctx, err)
}
if len(b.doneInfo) < 1 || !reflect.DeepEqual(b.doneInfo[0].Err, wantErr) {
t.Fatalf("b.doneInfo = %v; want b.doneInfo[0].Err = %v", b.doneInfo, wantErr)
}
if len(b.doneInfo) < 2 || !reflect.DeepEqual(b.doneInfo[1].Trailer, testTrailerMetadata) {
t.Fatalf("b.doneInfo = %v; want b.doneInfo[1].Trailer = %v", b.doneInfo, testTrailerMetadata)
}
}