Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Fix hangs when the reading from the native driver raised an error before all input was consumed #135

Merged
merged 2 commits into from
Jul 5, 2017
Merged

Fix hangs when the reading from the native driver raised an error before all input was consumed #135

merged 2 commits into from
Jul 5, 2017

Conversation

juanjux
Copy link
Contributor

@juanjux juanjux commented Jun 30, 2017

This fix was trivial to code, easy to explain but was a hell to debug.

When there was any error on the reader from the native driver, the driver stdin was not being consumed until the next newline. This caused that on the next request it would still trying to write to its stdout while the Go wrapper would try to read the new request into its stdin, hanging.

This also changes the read to be done by reading buffer-sized chunks into a slice so this should also fix the "buffer size exceeded" problem.

The driver images should be rebuild once this is merged since it's a pretty annoying bug.

@juanjux
Copy link
Contributor Author

juanjux commented Jul 1, 2017

Fixes bblfsh/bblfshd/issues/36.
Fixes #130.

@juanjux
Copy link
Contributor Author

juanjux commented Jul 1, 2017

PS: we should really add a lot more verbose debug logging now that it's selectable. Maybe also set the default logging level to "info". It would make a lot easier to debug problems since when testing with the server and drivers in containers and gRPC calls you can't just use gdb. Should I open an issue?

@codecov
Copy link

codecov bot commented Jul 1, 2017

Codecov Report

Merging #135 into master will increase coverage by 0.31%.
The diff coverage is 64.28%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #135      +/-   ##
=========================================
+ Coverage   40.18%   40.5%   +0.31%     
=========================================
  Files          21      21              
  Lines        2160    2185      +25     
=========================================
+ Hits          868     885      +17     
- Misses       1204    1212       +8     
  Partials       88      88
Impacted Files Coverage Δ
protocol/jsonlines/decoder.go 72.09% <64.28%> (-5.69%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5f90ffd...0db388f. Read the comment docs.

@@ -15,6 +14,7 @@ const (

type lineReader interface {
ReadLine() ([]byte, bool, error)
ReadSlice(delim byte) (line[] byte, err error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to replace ReadLine with ReadSlice instead of having both?

Copy link
Contributor Author

@juanjux juanjux Jul 4, 2017

Choose a reason for hiding this comment

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

Mmm, I think the code is simpler this way; ReadSlice returns (via parameter) a pointer (or pointers since it's a slice) to the original slice and don't block so it's perfect for the read-discard done on discardPending (no copying and no blocking). ReadLine on the other hand does a copy but also returns a specific code if the buffer is full so we can continue iterating by chunks, which it does on subsecuent calls.

Both could be implemented using the other but I think it's simpler that way in the places they're used here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, thanks for the explanation.

@@ -40,17 +40,41 @@ func NewDecoder(r io.Reader) Decoder {
return &decoder{r: lr}
}

func (d *decoder) discardPending() error {
// Read and discard everytihng until the next newline
Copy link
Contributor

Choose a reason for hiding this comment

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

s/everytihng/everything/

Copy link
Contributor

Choose a reason for hiding this comment

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

This line may be better above the function declaration, to document the 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.

Fixed*2, thanks.

// Read and discard everytihng until the next newline
for {
_, err := d.r.ReadSlice('\n')
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

this nested if and if-else may get simpler with a switch

Copy link
Contributor Author

@juanjux juanjux Jul 4, 2017

Choose a reason for hiding this comment

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

Definitely! (too many years doing too much Python can do this to a programmer mind).

chunk, isPrefix, err := d.r.ReadLine()
if err != nil {
if !isPrefix {
d.discardPending()
Copy link
Contributor

Choose a reason for hiding this comment

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

return value of this call should be checked, shouldn't it?

Copy link
Contributor Author

@juanjux juanjux Jul 4, 2017

Choose a reason for hiding this comment

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

Mmm, it's already inside an error handler so my logic was to return the original error, but on a second tough I'll also check that error and produce a new error with a combined message since any error to discard the input buffer could bring more misteriously hanged containers.

Copy link
Contributor Author

@juanjux juanjux Jul 4, 2017

Choose a reason for hiding this comment

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

PS: is probably undefined behaviour to do this with the bufio object once it has already failed, but I checked causing the failure and without the discard the next call would hang so it's probably the lesser evil.

@juanjux juanjux requested a review from alcortesm July 5, 2017 07:52
"io"
"fmt"
Copy link
Member

Choose a reason for hiding this comment

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

apply gofmt

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

var line []byte

for {
chunk, isPrefix, err := d.r.ReadLine()
Copy link
Member

Choose a reason for hiding this comment

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

Maybe move this code block to a smaller function (e.g. readLine(r lineReader) error) to avoid too much nesting and improve readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I also added a couple comments and simplified the return logic.

@juanjux juanjux merged commit 5fd7188 into bblfsh:master Jul 5, 2017
bzz added a commit to bzz/server that referenced this pull request Jul 5, 2017
This is motivated to have a version that includes latest bblfsh/sdk#135
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants