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

Implement is_empty() for BufReader #45369

Merged
merged 1 commit into from
Nov 6, 2017
Merged

Implement is_empty() for BufReader #45369

merged 1 commit into from
Nov 6, 2017

Conversation

fintelia
Copy link
Contributor

Simple implementation of is_empty method for BufReader so it is possible to tell whether there is any data in its buffer.

I didn't know correct stability annotation to place on the function. Presumably there is no reason to place this feature behind a feature flag, but I wasn't sure how to tag it as an unstable feature without that.

CC: #45323

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@frewsxcv frewsxcv added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Oct 18, 2017
@sfackler
Copy link
Member

What would code do in response to the emptyness or non-emptyness of the buffer?

@kennytm kennytm added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 18, 2017
@fintelia
Copy link
Contributor Author

If the buffer is non-empty, then the application might want to read data from it. However, if the buffer is empty the application might not want to issue a potentially expensive (or blocking) call to the underlying Reader just yet. It could also be issued before into_inner to ensure that no data will be lost.

In my case, I'm using some BufReaders to wrap non-blocking TcpStreams which I poll over using mio. Whenever a message arrives on one of them I read it from the indicated stream. However, to avoid the possible deadlock of polling on the underlying stream for an already buffered message, I must empty the buffer before polling again. But I can't know the buffer is empty without calling read() and having it return zero bytes, which means that I end up doing a bunch of extraneous syscalls just to learn the state of a userspace buffer.

@carols10cents
Copy link
Member

r? @sfackler (i think alex was traveling and is traveling)

@fintelia
Copy link
Contributor Author

It is also worth considering if it would make sense to have a len or get_buffer method instead or in addition. Any of these could be implemented in terms of the others using the existing fill_buffer method (which fills the buffer iff it is currently empty, and returns a reference to it either way).

@carols10cents
Copy link
Member

ping @rust-lang/libs, could one of yinz be a new reviewer on this please?

@BurntSushi
Copy link
Member

In my case, I'm using some BufReaders to wrap non-blocking TcpStreams which I poll over using mio. Whenever a message arrives on one of them I read it from the indicated stream. However, to avoid the possible deadlock of polling on the underlying stream for an already buffered message, I must empty the buffer before polling again. But I can't know the buffer is empty without calling read() and having it return zero bytes, which means that I end up doing a bunch of extraneous syscalls just to learn the state of a userspace buffer.

Could you expand on this a bit? I don't think I understand it. For example, I don't know why deadlock is a concern here.

@fintelia
Copy link
Contributor Author

fintelia commented Oct 30, 2017

@BurntSushi Consider the following sequence of events:

  1. Client A sends two messages, and waits for replies to both
  2. The server wakes up when epoll detects that there is data to be read off client A's TCP stream
  3. The server calls BufReader::read() and gets back the first message. However, the BufReader has actually read both messages into its internal buffer using a single read syscall.
  4. The server replies to the first message.
  5. Then the server calls epoll again. Since there is no data in the kernel waiting to be read, it blocks forever.
  6. Client A gets the first reply, but still block waiting for the second.

At this point neither the server nor the client can make forward progress, and are thus deadlocked. In fact, even if the server gets messages from other clients it still won't become unblocked, because it has no reason to check for messages from client A.

@carols10cents
Copy link
Member

r? @BurntSushi, does @fintelia's comment explain things sufficiently?

@rust-highfive rust-highfive assigned BurntSushi and unassigned sfackler Nov 6, 2017
@BurntSushi
Copy link
Member

@fintelia Thanks for clarifying! I think that motivation seems good enough for me. @bors r+

@bors
Copy link
Contributor

bors commented Nov 6, 2017

📌 Commit df4b781 has been approved by BurntSushi

@BurntSushi
Copy link
Member

@carols10cents Thanks for the ping. :-)

@bors
Copy link
Contributor

bors commented Nov 6, 2017

⌛ Testing commit df4b781 with merge 58557fa...

bors added a commit that referenced this pull request Nov 6, 2017
Implement is_empty() for BufReader

Simple implementation of `is_empty` method for BufReader so it is possible to tell whether there is any data in its buffer.

I didn't know correct stability annotation to place on the function. Presumably there is no reason to place this feature behind a feature flag, but I wasn't sure how to tag it as an unstable feature without that.

CC: #45323
@bors
Copy link
Contributor

bors commented Nov 6, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: BurntSushi
Pushing 58557fa to master...

@bors bors merged commit df4b781 into rust-lang:master Nov 6, 2017
@jonhoo
Copy link
Contributor

jonhoo commented Nov 6, 2017

@BurntSushi this has feature = "bufreader_is_empty". Should an entry be added to the unstable book? Or the feature gate be removed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants