-
Notifications
You must be signed in to change notification settings - Fork 59
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
Concurrent requests #57
Conversation
Here's the remaining work required to handle the This brings the following improvement:
The only change required in the server is:
EDIT: I had correctness issues. I updated the results above. The gain is small, ~4s. |
func BenchmarkQuery(b *testing.B) { | ||
c := &Config{ | ||
ServerURI: *integrationServerFlag, | ||
SessionProperties: map[string]string{"query_priority": "1"}, |
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.
what is it for?
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.
I'm not sure, I copied this config from other tests :-)
} | ||
go func() { | ||
// drain errors chan to allow goroutines to write to it | ||
for range st.errors { |
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.
I do not quite get it? What would happen if we did not run active drain loop here? Would go routines writing to st.error
block?
Then what would happen if we want to write to st.errors
and Close()
was not called? Do we assume that then fetch()
is running and the erros
channels is being read from?
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.
- If an error happens in any of the two goroutines, they write errors to
errors
. fetch()
consumes the first error and returns it to the user, who's responsible for closing the whole statement.Close()
closes up all channels, which will allow goroutines to finish, but before they do that, more errors can happen. These are ignored because the errors channel is drained.
Both goroutines exit after the first error, but there could be a very rare case when we receive a malformed response AND the next HTTP request will fail. The HTTP request can fail first, but there can be an error in the other goroutine when trying to decode the previous response. Draining this errors channel handles this.
If the user doesn't call Close()
, the goroutines can remain blocked on trying to write to full channels, either the regular one for results or the errors channel.
Dealing with all of this is forced by running tests with the race detector (go test -race
), which fails if there's any possible race. This requires closing all the channels in the right order.
I need to add a test for a query with a larger number of result rows to make sure we're not dropping any rows. |
62c12bc
to
9d1fc1f
Compare
9d1fc1f
to
019254e
Compare
LGTM - are there any outstanding changes you want to do here @nineinchnick ? |
@losipiuk it's ready to go, thanks! |
Introduce two goroutines for making HTTP requests and decoding the JSON payload concurrently. This brings only a minor improvement (see benchmarks below) unless the server can send the
nextUri
as an HTTP header, so the next request can be made immediately, without waiting to decode the payload.Before:
After: