-
-
Notifications
You must be signed in to change notification settings - Fork 423
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
Read ordered chunks from RecvStream #952
Conversation
99d6a16
to
c925a15
Compare
hash_map::Entry::Occupied(e) => e, | ||
}; | ||
let rs = entry.get_mut(); | ||
match rs.read_chunk() { |
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 is pretty repetitive, can we factor out a bunch of the match here (ideally in a separate commit)? Could apply to read_unordered()
as well, ideally, but just between read()
and read_chunk()
would be good if that makes it hard.
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 got a solution I find a little complex in feb3b63, what do you think about this?
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.
It looks like you can just inline the IntoReadResult
into the closure passed to try_read()
? We already have the nested map()
calls anyway. Or am I missing something?
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.
Ho yeah maybe ! 😅
For the moment I get stuck because self.add_read_credits(len as u64)
needs to mutate self
to compute transmit_max_data
, and it is already mutably borrowed by the closure. But I'll try a little harder in a bit.
if let Some(bytes) = self.assembler.read_chunk()? { | ||
Ok(Some(bytes)) | ||
} else { | ||
self.read_blocked().map(|()| None) | ||
} |
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.
A match
expression would be more readable and more compact, I think?
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.
done
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.
Thanks for working on this!
quinn/src/streams.rs
Outdated
@@ -347,6 +347,11 @@ where | |||
} | |||
} | |||
|
|||
/// [`read_chunk()`]: RecvStream::read_chunk |
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 should be documented, including an explicit warning against relying on the chunk boundaries having any particular relationship to the sender's writes.
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 got this a better comment. I'm not sure I grasped everything you'd like it to say?
0f6bece
to
c1594b4
Compare
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.
Wording tweaks for the comments:
quinn/src/streams.rs
Outdated
ReadChunk { stream: self } | ||
} | ||
|
||
/// [`read_chunk()`]: RecvStream::read_chunk |
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.
/// [`read_chunk()`]: RecvStream::read_chunk | |
/// Foundation of [`read_chunk()`]: RecvStream::read_chunk |
quinn/src/streams.rs
Outdated
self.poll_read_generic(cx, |conn, stream| conn.inner.read_unordered(stream)) | ||
} | ||
|
||
/// Read the next segment of data from next valid offset in the stream. |
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.
/// Read the next segment of data from next valid offset in the stream. | |
/// Read the next segment of data |
quinn/src/streams.rs
Outdated
/// Yields a segment of data consecutive to the last ordered read offset, or `None` | ||
/// if the stream was finished. Segments are received in order. | ||
/// | ||
/// Beware, the returned chunks bounds won't always match those written by the peer. | ||
/// | ||
/// Chunk reads have reduced overhead and higher throughput, and should therefore be | ||
/// preferred when applicable. |
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.
Tweaked wording a bit:
/// Yields a segment of data consecutive to the last ordered read offset, or `None` | |
/// if the stream was finished. Segments are received in order. | |
/// | |
/// Beware, the returned chunks bounds won't always match those written by the peer. | |
/// | |
/// Chunk reads have reduced overhead and higher throughput, and should therefore be | |
/// preferred when applicable. | |
/// Yields a segment of data beginning immediately after the last data yielded by | |
/// `read` or `read_chunk`, or `None` if the stream was finished. | |
/// | |
/// Slightly more efficient than `read` due to not copying. Chunks boundaries | |
/// do not correspond to peer writes, and hence cannot be used as framing. |
quinn-proto/src/connection/mod.rs
Outdated
/// window is filled. When in-order delivery is required, the siblings `read()` or `read_chunk()` | ||
/// method should be used. |
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.
/// window is filled. When in-order delivery is required, the siblings `read()` or `read_chunk()` | |
/// method should be used. | |
/// window is filled. When in-order delivery is required, the sibling `read()` or `read_chunk()` | |
/// methods should be used. |
c1594b4
to
66e55a5
Compare
(Note that #961 is blocked on this, so would be nice to follow through soon...) |
My wording in #961 was unclear--I don't actually consider it blocked, I'm just holding off on adding additional refactoring that would make rebasing this PR harder than it otherwise would be. |
While we are at it: I would also appreciate a vectored read API - which can retrieve more than 1 chunk at a time. Because locking a Mutex and potentially doing a task wakeup for reading just 1kB of data (due to Quic packet sizes) is fairly unefficient. One API I've used in a project for that is:
Where the caller provides an array (initialized with dummy elements / |
66e55a5
to
34b892c
Compare
I finally got the read methods factorization right (yeah the I've addesd a test for All the wording changes have been addressed. A new commit contains @Matthias247 suggestion. This is still WIP as I'm waiting for your feedback on this public API change, and it should probably be tested in the functional test module. |
Did you see #955? |
34b892c
to
cad6f1a
Compare
I should probably have paid more attention, sorry... Now the |
cad6f1a
to
4840713
Compare
Maybe @Ralith or @Matthias247 want to take a look which version they prefer. |
|
||
if chunk.offset > self.bytes_read { | ||
// Next chunk is after current read index | ||
return Ok(None); |
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.
Isn't None
end of stream? i'm not sure how this function is used, but it might need to return a blocked status instead.
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 method works as it's siblings: it returns None
when there is nothing to assemble. Blocked status is managed at the stream level in quinn-proto::connection::streams::Streams::read_chunk()
.
See the chunks_dedup()
test at the end of this file for an example of expected behavior.
I skimmed both commits, and I have a slight preference for this one since I found the I think this change currently has a good balance between code reuse and readability. @stammw Also thanks for incorporating my feedback! |
4840713
to
6fbfc6e
Compare
The current I've added a test 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.
LGTM, modulo small doc nits.
quinn/src/streams.rs
Outdated
/// Slightly more efficient than `read` due to not copying. Chunks boundaries | ||
/// do not correspond to peer writes, and hence cannot be used as framing. |
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.
/// Slightly more efficient than `read` due to not copying. Chunks boundaries | |
/// do not correspond to peer writes, and hence cannot be used as framing. | |
/// Slightly more efficient than `read` due to not copying. Chunk boundaries | |
/// do not correspond to peer writes, and hence cannot be used as framing. |
quinn/src/streams.rs
Outdated
/// Slightly more efficient than `read` due to not copying. Chunks boundaries | ||
/// do not correspond to peer writes, and hence cannot be used as framing. |
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.
/// Slightly more efficient than `read` due to not copying. Chunks boundaries | |
/// do not correspond to peer writes, and hence cannot be used as framing. | |
/// Slightly more efficient than `read` due to not copying. Chunk boundaries | |
/// do not correspond to peer writes, and hence cannot be used as framing. |
6fbfc6e
to
6eeda35
Compare
Should be ok now. Happy to contribute to quinn a bit :) |
Hello !
I've started trying to implement #929.
Still I'd better be adding some tests before its ready. So I'm setting this PR WIP for a first feedback.