Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This does not account for
nc.Opts.ReconnectBufSize
, which is worrisome that tests pass, which means that this is not properly tested.More importantly, in which situation would you get this called so many times and so fast that the GC would not collect those buffers? Maybe we need to understand better why this is a problem in the first place.
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.
@kozlovic thanks for the feedback!
The tests likely passed because
bufio.NewWriterSize(W, N)
does nothing to limit the amount of data writtenio.Writer
W - N here is only used to size the internal buffer. Properly limiting the amount of data writted to W would need to be handled by W - implementing aLimitedWriter
like io.LimitedReader and wrapping the buffer passed tonc.pending
would work - this would likely require updating the error handling around reconnects.The reason this was spinning so hard and generating loads of garbage was that we use ginkgo for our tests and it encourages some
nastyinteresting patterns - like spinning up anats
listener for each test irregardless of whether it has something to connect to - it is spun down at the end of each test, but who knows what the connection state is then. Because of the nastiness ginkgo introduces it does tend to highlight situations where applications do not perform well when error'ing.That said, this is an edge case that occurs only when error'ing in a tight loop in test code, but an 8Mb memory allocation per reconnect is still a pretty heavy hit (regardless of the efficacy of Go's GC).
Thanks again for reviewing and please let me know if there is anything I may do to help.
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.
Yes, the underlying bytes buffer is never limiting the amount of data that can be written. We actually do check for length in the
publish()
call to enforce that limit (this is to avoid unbound growth).Let me investigate a bit more to see why the original code would need so much memory, but otherwise I think your changes are good. Thanks!