-
Notifications
You must be signed in to change notification settings - Fork 126
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
Add support for WebTransport SendOrder to neqo (issue #1432) #1437
Conversation
…s within a sendorder (or for unordered streams) is attempted
…s within a sendorder (or for unordered streams) is attempted
I had added the custom Ord impl to switch the order, but didn't actually modify it to switch the order... :-) |
I think we should have some tests in neqo as well. |
neqo-http3/src/features/extended_connect/webtransport_session.rs
Outdated
Show resolved
Hide resolved
assert_eq!( | ||
out.as_dgram_ref().is_some(), | ||
(d_num + 1) % usize::try_from(DEFAULT_ACK_PACKET_TOLERANCE + 1).unwrap() == 0 | ||
); |
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.
We're not really testing for ACKs, so maybe you don't need to worry about checking 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.
Cut-and-paste from the next test, I can remove that
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.
Though if I make it a function I might want to keep it
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 noticed there are some failed tests, so I think this patch still has more to do.
neqo-http3/src/features/extended_connect/webtransport_session.rs
Outdated
Show resolved
Hide resolved
…essed in stream_id order; the other was a bug in remove_terminal()
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 looks good to me, but I think this still needs @martinthomson 's approval.
neqo-transport/src/send_stream.rs
Outdated
// This avoids the complexity of trying to hold references to the | ||
// Streams which are owned by the IndexMap. | ||
sendordered: BTreeMap<SendOrder, HashSet<StreamId>>, | ||
regular: Vec<StreamId>, // streams with no SendOrder set, sorted in stream_id order |
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.
Did you consider iterating map
instead? You would need to mark any stream that has a sendorder somehow (i.e., skip if self.sendorder.is_some()
), but then you save the overhead of maintaining this collection.
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.
Possibly, but: In stream-per-frame (and perhaps most instances where sendorder is used), all or almost all the streams will have sendorders, and so we'll iterate over map but ignore almost or all the iterations. That seems a higher overhead (every time we're sending packets) than the maintenance overhead.
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.
Hmm. Having a count of the number of unordered streams would allow us to add .take(count)
when iterating, which would shortcut very nicely. WDYT?
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 understand your suggestion here
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, rather than maintaining a collection of streams that are unordered, you merely kept a count, then in the two cases we think most likely:
- All streams are unordered. You iterate over the main
IndexMap
directly, but.take(x)
wherex = self.map.len()
, means that it is a full iteration. - All streams are ordered. You iterate over the main
IndexMap
, but.take(0)
, which turns into a no-op.
The advantage is that you don't have an indirection for the first iteration; you iterate the collection directly. In the second, you short-circuit that iteration (because iterators are lazy and .take(0)
doesn't hit the underlying iterator at all. It's only when you have a mix that you end up paying extra, but that's not a situation we think likely. If there are a few streams that are unordered, then you'll have a few to track, but maybe you can count the number of unordered streams with unsent data so that you have to hit the collection less often.
fn set_sendorder(&mut self, _conn: &mut Connection, _sendorder: Option<SendOrder>) { | ||
// Not relevant on session | ||
} |
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 think that we should let this pass through. We will simply not call it in gecko (who knows, maybe this makes sense at some point).
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.
Pass through to where?
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 am suggesting that you change the send order, rather than do nothing
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.
Sessions don't have a sendorder to set, so I'm still confused by your suggestion. Unless you mean "set the sendorder of all streams to N", which would be unhelpful and there's no reason for it.
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.
No, I'm just suggesting that you change the session stream's sendorder. Yes, it doesn't make much sense, but a no-op is far more surprising than a function that does the expected thing, even if it shouldn't 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.
Maybe add a debug assertion here?
I assume this function should not be called at all.
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 don't see why this wouldn't work:
self.borrow_mut().control_stream_send.set_sendorder(conn, sendorder)
Updated for almost all the comments; will look at using Vec instead of HashSet for each sendordered group tomorrow |
@jesup please also fix all format and clippy errors. Thanks. |
fn set_sendorder(&mut self, _conn: &mut Connection, _sendorder: Option<SendOrder>) { | ||
// Not relevant on session | ||
} |
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 don't see why this wouldn't work:
self.borrow_mut().control_stream_send.set_sendorder(conn, sendorder)
neqo-http3/src/lib.rs
Outdated
/// # Errors | ||
/// Error my occure during sending data, e.g. protocol error, etc. | ||
/// Error my occur during sending data, e.g. protocol error, etc. |
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.
/// Error my occur during sending data, e.g. protocol error, etc. | |
/// Errors might occur during sending data, e.g., protocol error. |
neqo-http3/src/send_message.rs
Outdated
@@ -271,6 +271,10 @@ impl SendStream for SendMessage { | |||
self.stream.has_buffered_data() | |||
} | |||
|
|||
fn set_sendorder(&mut self, _conn: &mut Connection, _sendorder: Option<SendOrder>) { | |||
// Not relevant for SendMessage |
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.
Again. self.stream.set_sendorder(conn, sendorder)
seems workable here, even if we don't end up using it. (Yes, this requires an additional step to implement that on BufferedStream
, but it's a trivial thing.)
Yes, we're building for webtransport, but this type has a direct relationship with an underlying stream and a random noop is a surprise I'd prefer to avoid.
stream_id: StreamId, | ||
} | ||
|
||
#[cfg(test)] |
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.
#[cfg(test)] |
neqo-transport/src/streams.rs
Outdated
if self.sendorder.is_some() && other.sendorder.is_some() { | ||
// We want reverse order (high to low) when both values are specified. | ||
other.sendorder.cmp(&self.sendorder) |
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.
The alternative (I keep coming up with these, sorry) might be better:
if self.sendorder.is_some() && other.sendorder.is_some() { | |
// We want reverse order (high to low) when both values are specified. | |
other.sendorder.cmp(&self.sendorder) | |
if let (Some(s), Some(o)) = (&self.sendorder, &other.sendorder) { | |
// We want reverse order (high to low) when both values are specified. | |
o.cmp(s) |
neqo-transport/src/streams.rs
Outdated
self.send.insert( | ||
new_id, 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.
Is this really what cargo fmt produces? I'm surprised that it's breaking across lines like this.
neqo-transport/src/connection/mod.rs
Outdated
/// # Errors | ||
/// 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.
/// # Errors | |
/// None |
neqo-http3/src/connection.rs
Outdated
/// Set the stream SendOrder. | ||
/// # Errors | ||
/// Returns InvalidStreamId if the stream id doesn't exist |
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.
Clippy will complain here.
/// Set the stream SendOrder. | |
/// # Errors | |
/// Returns InvalidStreamId if the stream id doesn't exist | |
/// Set the stream `SendOrder`. | |
/// # Errors | |
/// `InvalidStreamId` if the stream id doesn't exist. |
This was landed as part of PR #1443 |
No attempt at fairness within a sendorder (or for unordered streams) is attempted.
A few typos are corrected as well