-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stats: Add RPC event for blocking for a picker update #6422
Changes from 3 commits
942bdd9
dc4e6b8
1361dcc
e69d389
5ec681a
ff3dda4
906ed7d
e6d27af
00f02a5
a5d9ad2
624eaf2
9fa6112
4685c89
7a796d9
8e40bc1
e1a01c2
1daf196
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,21 +28,26 @@ import ( | |
"google.golang.org/grpc/internal/channelz" | ||
istatus "google.golang.org/grpc/internal/status" | ||
"google.golang.org/grpc/internal/transport" | ||
"google.golang.org/grpc/stats" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
// pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick | ||
// actions and unblock when there's a picker update. | ||
type pickerWrapper struct { | ||
mu sync.Mutex | ||
done bool | ||
idle bool | ||
blockingCh chan struct{} | ||
picker balancer.Picker | ||
mu sync.Mutex | ||
done bool | ||
idle bool | ||
blockingCh chan struct{} | ||
picker balancer.Picker | ||
statsHandlers []stats.Handler | ||
} | ||
|
||
func newPickerWrapper() *pickerWrapper { | ||
return &pickerWrapper{blockingCh: make(chan struct{})} | ||
func newPickerWrapper(statsHandlers []stats.Handler) *pickerWrapper { | ||
return &pickerWrapper{ | ||
blockingCh: make(chan struct{}), | ||
statsHandlers: statsHandlers, | ||
} | ||
} | ||
|
||
// updatePicker is called by UpdateBalancerState. It unblocks all blocked pick. | ||
|
@@ -125,6 +130,10 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. | |
return nil, balancer.PickResult{}, status.Error(codes.Canceled, errStr) | ||
} | ||
case <-ch: | ||
for _, sh := range pw.statsHandlers { | ||
sh.HandleRPC(ctx, &stats.PickerUpdated{}) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: nix newline. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah whoops. Deleted newline. |
||
} | ||
continue | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,27 @@ func (s *Begin) IsClient() bool { return s.Client } | |
|
||
func (s *Begin) isRPCStats() {} | ||
|
||
// InitialResolverResult represents an event that the resolved finished | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved->resolver There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Switched. |
||
// resolving if the ClientConn blocks on resolver resolution while performing a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "...if the RPC occurred before the initial resolver result."? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My string is still technically correct, but yours falls under the subset of my language and is more specific :). Switched. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an external docstring, so we should find something that is as clear and concise as possible. "blocks on resolver resolution" is confusing to read and technically the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, I agree. Will push once I finish tests. |
||
// RPC. | ||
type InitialResolverResult struct{} | ||
|
||
// IsClient indicates if the stats information is from client side. Only Client | ||
// Side interfaces with a resolver, thus always returns true. | ||
func (irr *InitialResolverResult) IsClient() bool { return true } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nit for all these methods. Since the receiver is not used, we don't even have to name it. So, this can simply be: func (*InitialResolverResult) IsClient() bool { return true } There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmmmm ok I was actually wondering that too. Deleted, thanks. |
||
|
||
func (irr *InitialResolverResult) isRPCStats() {} | ||
|
||
// PickerUpdated represents an event that the picker finished picking if the | ||
// ClientConn blocks on picker picking while performing a RPC. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "PickerUpdated indicates that the LB Policy's picker was updated after the previous pick attempt returned ErrNoSubConnAvailable." Or something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is the only case that this gets triggered (see list of 4 in https://github.com/grpc/grpc-go/blob/master/picker_wrapper.go#L87). Any other ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's true. I was trying to keep it simple. The alternative would be something more vague like "PickerUpdated indicates that the LB policy provided a new picker while the RPC was waiting for one." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's do the more vague one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure.. "picker finished picking if the CC blocks on picker picking" makes no sense to me 😛 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please update to something like |
||
type PickerUpdated struct{} | ||
|
||
// IsClient indicates if the stats information is from client side. Only Client | ||
// Side interfaces with a Picker, thus always returns true. | ||
func (pu *PickerUpdated) IsClient() bool { return true } | ||
|
||
func (pu *PickerUpdated) isRPCStats() {} | ||
|
||
// InPayload contains the information for an incoming payload. | ||
type InPayload struct { | ||
// Client is true if this InPayload is from client side. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -543,6 +543,8 @@ func (s) TestRetryStats(t *testing.T) { | |
handler.mu.Lock() | ||
want := []stats.RPCStats{ | ||
&stats.Begin{}, | ||
&stats.PickerUpdated{}, | ||
&stats.PickerUpdated{}, | ||
&stats.OutHeader{FullMethod: "/grpc.testing.TestService/EmptyCall"}, | ||
&stats.OutPayload{WireLength: 5}, | ||
&stats.End{}, | ||
|
@@ -579,7 +581,7 @@ func (s) TestRetryStats(t *testing.T) { | |
// There is a race between receiving the payload (triggered by the | ||
// application / gRPC library) and receiving the trailer (triggered at the | ||
// transport layer). Adjust the received stats accordingly if necessary. | ||
const tIdx, pIdx = 13, 14 | ||
const tIdx, pIdx = 15, 16 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Existing tests should probably filter out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
_, okT := handler.s[tIdx].(*stats.InTrailer) | ||
_, okP := handler.s[pIdx].(*stats.InPayload) | ||
if okT && okP { | ||
|
@@ -594,7 +596,11 @@ func (s) TestRetryStats(t *testing.T) { | |
t.Fatalf("at position %v: got %T; want %T", i, s, w) | ||
} | ||
wv, sv := reflect.ValueOf(w).Elem(), reflect.ValueOf(s).Elem() | ||
|
||
if sv.NumField() == 0 { | ||
// Resolver blocking and Picker blocking events have no fields, | ||
// isClient() always returns true. | ||
continue | ||
} | ||
// Validate that Client is always true | ||
if sv.FieldByName("Client").Interface().(bool) != true { | ||
t.Fatalf("at position %v: got Client=false; want true", i) | ||
|
@@ -620,8 +626,8 @@ func (s) TestRetryStats(t *testing.T) { | |
} | ||
|
||
// Validate timings between last Begin and preceding End. | ||
end := handler.s[8].(*stats.End) | ||
begin := handler.s[9].(*stats.Begin) | ||
end := handler.s[10].(*stats.End) | ||
begin := handler.s[11].(*stats.Begin) | ||
diff := begin.BeginTime.Sub(end.EndTime) | ||
if diff < 10*time.Millisecond || diff > 50*time.Millisecond { | ||
t.Fatalf("pushback time before final attempt = %v; want ~10ms", diff) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a comment here or where
statsHandler
field is defined about what this is for and how this is used?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment on field: statsHandlers []stats.Handler // to record blocking picker calls