Skip to content
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

transport: fix race between applying and acking flow-control settings frames #1630

Merged
merged 7 commits into from
Oct 31, 2017

Conversation

MakMukhi
Copy link
Contributor

fixes #1626 #1564

}
t.applySettings(i.rs)
t.controlBuf.put(&settingsAck{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not apply settings before enqueuing the ack the first time?

This results in more delay in processing the ack (it has to make it through the control buffer twice), and it splits up the code that handles settings, which makes it harder to reason about.

If there's some reason we have to do it this way, that's fine but we should put comments in to explain it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was in fact thinking about that last night. The code sort of evolved to be this way and you're right it makes more sense to apply the settings in the settings handler itself.

@dfawley dfawley self-assigned this Oct 27, 2017
t.mu.Unlock()
case http2.SettingInitialWindowSize:
t.mu.Lock()
if s.Val < t.streamSendQuota {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we be comparing this to t.initialWindowSize?

Also, do we have to take a lock for this field or t.maxStreams? I was thinking the only thing that should be changing these fields is the handling of a settings frame (so, this code here)...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.initialWindowSize controls our inbound window size while t.streamSendQuota controls our outbound window size. So, when we get a settings frame to update our initial window size( the outbound one) we update this variable.

You're right about t.maxStreams; updating it never required a lock. I copied the original code and made the same mistake!

func (t *http2Client) isRestrictive(s http2.Setting) bool {
switch s.ID {
case http2.SettingMaxConcurrentStreams:
if int(s.Val) < t.maxStreams {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional (but recommended): return int(s.Val) < t.maxStreams

rs = append(rs, s)
} else {
ps = append(ps, s)
}
return nil
})
if isFirst && isMaxConcurrentStreamsMissing {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional, maybe for a later refactor:

The code might be cleaner with two implementations: handleSettings and handleInitialSettings. handleInitialSettings doesn't need to check restrictive/permissive -- just apply all the settings and write the ack. Then the special-case code checking for max concurrent streams is removed from the ongoing handleSettings function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same logic, acking after applying restrictive settings and before applying permissive settings, holds for handleInitialSettings. The client doesn't wait for the server to send initial settings before starting streams.
We'll still need to check if http2.SettingMaxConcurrentStreams is present or not in the initial settings. So we will only be able to save one conditional check by creating this other function.

@MakMukhi MakMukhi merged commit 246b2f7 into grpc:master Oct 31, 2017
MakMukhi added a commit that referenced this pull request Nov 1, 2017
@dfawley dfawley changed the title Fix settings ack race transport: fix race between applying and acking flow-control settings frames Nov 6, 2017
@menghanl menghanl added this to the 1.8 Release milestone Nov 7, 2017
@MakMukhi MakMukhi deleted the fix_settings_ack_race branch May 4, 2018 02:04
@lock lock bot locked as resolved and limited conversation to collaborators Oct 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Race in applying settings and acking
3 participants