@@ -91,6 +91,10 @@ func (p *rlsPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
9191 p .lb .cacheMu .Lock ()
9292 var pr balancer.PickResult
9393 var err error
94+
95+ // Record metrics without the cache mutex held, to prevent lock contention
96+ // between concurrent RPC's and their Pick calls. Metrics Recording can
97+ // potentially be expensive.
9498 metricsCallback := func () {}
9599 defer func () {
96100 p .lb .cacheMu .Unlock ()
@@ -160,6 +164,21 @@ func (p *rlsPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
160164 }
161165}
162166
167+ // errToPickResult is a helper function which converts the error value returned
168+ // by Pick() to a string that represents the pick result.
169+ func errToPickResult (err error ) string {
170+ if err == nil {
171+ return "complete"
172+ }
173+ if errors .Is (err , balancer .ErrNoSubConnAvailable ) {
174+ return "queue"
175+ }
176+ if _ , ok := status .FromError (err ); ok {
177+ return "drop"
178+ }
179+ return "fail"
180+ }
181+
163182// delegateToChildPoliciesLocked is a helper function which iterates through the
164183// list of child policy wrappers in a cache entry and attempts to find a child
165184// policy to which this RPC can be routed to. If all child policies are in
@@ -178,13 +197,15 @@ func (p *rlsPicker) delegateToChildPoliciesLocked(dcEntry *cacheEntry, info bala
178197 // X-Google-RLS-Data header.
179198 res , err := state .Picker .Pick (info )
180199 if err != nil {
181- pr := "fail"
182- if _ , ok := status .FromError (err ); ok {
183- pr = "drop"
184- }
185- return res , func () {
200+ pr := errToPickResult (err )
201+ rf := func () {
186202 targetPicksMetric .Record (p .metricsRecorder , 1 , p .grpcTarget , p .rlsServerTarget , cpw .target , pr )
187- }, err
203+ }
204+ if pr == "queue" {
205+ // Don't record metrics for queued Picks.
206+ rf = func () {}
207+ }
208+ return res , rf , err
188209 }
189210
190211 if res .Metadata == nil {
@@ -210,16 +231,15 @@ func (p *rlsPicker) useDefaultPickIfPossible(info balancer.PickInfo, errOnNoDefa
210231 if p .defaultPolicy != nil {
211232 state := (* balancer .State )(atomic .LoadPointer (& p .defaultPolicy .state ))
212233 res , err := state .Picker .Pick (info )
213- pr := "complete"
214- if err != nil {
215- pr = "fail"
216- if _ , ok := status .FromError (err ); ok {
217- pr = "drop"
218- }
234+ pr := errToPickResult (err )
235+ rf := func () {
236+ targetPicksMetric .Record (p .metricsRecorder , 1 , p .grpcTarget , p .rlsServerTarget , p .defaultPolicy .target , pr )
237+ }
238+ if pr == "queue" {
239+ // Don't record metrics for queued Picks.
240+ rf = func () {}
219241 }
220- return res , func () {
221- defaultTargetPicksMetric .Record (p .metricsRecorder , 1 , p .grpcTarget , p .rlsServerTarget , p .defaultPolicy .target , pr )
222- }, err
242+ return res , rf , err
223243 }
224244
225245 return balancer.PickResult {}, func () {
0 commit comments