Skip to content

Commit 97c9a08

Browse files
committed
perf: avoid relocking response stream references
1 parent c9d619c commit 97c9a08

4 files changed

Lines changed: 36 additions & 25 deletions

File tree

src/client.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ pub struct Connection<T, B: Buf = Bytes> {
236236
#[derive(Debug)]
237237
#[must_use = "futures do nothing unless polled"]
238238
pub struct ResponseFuture {
239-
inner: proto::OpaqueStreamRef,
239+
inner: Option<proto::OpaqueStreamRef>,
240+
stream_id: crate::StreamId,
240241
push_promise_consumed: bool,
241242
}
242243

@@ -517,15 +518,16 @@ where
517518
self.inner
518519
.send_request(request, end_of_stream, self.pending.as_ref())
519520
.map_err(Into::into)
520-
.map(|(stream, is_full)| {
521+
.map(|(stream, response, is_full)| {
521522
if stream.is_pending_open() && is_full {
522523
// Only prevent sending another request when the request queue
523524
// is not full.
524525
self.pending = Some(stream.clone_to_opaque());
525526
}
526527

527528
let response = ResponseFuture {
528-
inner: stream.clone_to_opaque(),
529+
stream_id: crate::StreamId::from_internal(response.stream_id()),
530+
inner: Some(response),
529531
push_promise_consumed: false,
530532
};
531533

@@ -1469,21 +1471,21 @@ impl Future for ResponseFuture {
14691471
type Output = Result<Response<RecvStream>, crate::Error>;
14701472

14711473
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1472-
let (parts, _) = ready!(self.inner.poll_response(cx))?.into_parts();
1473-
let body = RecvStream::new(FlowControl::new(self.inner.clone()));
1474+
let inner = self
1475+
.inner
1476+
.as_mut()
1477+
.expect("ResponseFuture polled after completion");
1478+
let (parts, _) = ready!(inner.poll_response(cx))?.into_parts();
1479+
let body = RecvStream::new(FlowControl::new(self.inner.take().unwrap()));
14741480

14751481
Poll::Ready(Ok(Response::from_parts(parts, body)))
14761482
}
14771483
}
14781484

14791485
impl ResponseFuture {
14801486
/// Returns the stream ID of the response stream.
1481-
///
1482-
/// # Panics
1483-
///
1484-
/// If the lock on the stream store has been poisoned.
14851487
pub fn stream_id(&self) -> crate::StreamId {
1486-
crate::StreamId::from_internal(self.inner.stream_id())
1488+
self.stream_id
14871489
}
14881490

14891491
/// Polls for informational responses (1xx status codes).
@@ -1498,7 +1500,11 @@ impl ResponseFuture {
14981500
&mut self,
14991501
cx: &mut Context<'_>,
15001502
) -> Poll<Option<Result<Response<()>, crate::Error>>> {
1501-
self.inner.poll_informational(cx).map_err(Into::into)
1503+
self.inner
1504+
.as_mut()
1505+
.expect("ResponseFuture polled after completion")
1506+
.poll_informational(cx)
1507+
.map_err(Into::into)
15021508
}
15031509

15041510
/// Returns a stream of PushPromises
@@ -1513,7 +1519,7 @@ impl ResponseFuture {
15131519
}
15141520
self.push_promise_consumed = true;
15151521
PushPromises {
1516-
inner: self.inner.clone(),
1522+
inner: self.inner.as_ref().unwrap().clone(),
15171523
}
15181524
}
15191525
}
@@ -1535,7 +1541,8 @@ impl PushPromises {
15351541
Poll::Ready(Some(Ok((request, response)))) => {
15361542
let response = PushedResponseFuture {
15371543
inner: ResponseFuture {
1538-
inner: response,
1544+
stream_id: crate::StreamId::from_internal(response.stream_id()),
1545+
inner: Some(response),
15391546
push_promise_consumed: false,
15401547
},
15411548
};
@@ -1589,10 +1596,6 @@ impl Future for PushedResponseFuture {
15891596

15901597
impl PushedResponseFuture {
15911598
/// Returns the stream ID of the response stream.
1592-
///
1593-
/// # Panics
1594-
///
1595-
/// If the lock on the stream store has been poisoned.
15961599
pub fn stream_id(&self) -> crate::StreamId {
15971600
self.inner.stream_id()
15981601
}

src/proto/streams/store.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ pub(crate) struct Key {
2929
stream_id: StreamId,
3030
}
3131

32+
impl Key {
33+
pub(crate) fn stream_id(self) -> StreamId {
34+
self.stream_id
35+
}
36+
}
37+
3238
// We can never have more than `StreamId::MAX` streams in the store,
3339
// so we can save a smaller index (u32 vs usize).
3440
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

src/proto/streams/streams.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ where
264264
mut request: Request<()>,
265265
end_of_stream: bool,
266266
pending: Option<&OpaqueStreamRef>,
267-
) -> Result<(StreamRef<B>, bool), SendError> {
267+
) -> Result<(StreamRef<B>, OpaqueStreamRef, bool), SendError> {
268268
use super::stream::ContentLength;
269269
use http::Method;
270270

@@ -344,14 +344,16 @@ where
344344

345345
// TODO: ideally, OpaqueStreamRefs::new would do this, but we're holding
346346
// the lock, so it can't.
347-
me.refs += 1;
347+
me.refs += 2;
348348

349349
let is_full = me.counts.next_send_stream_will_reach_capacity();
350+
let response = OpaqueStreamRef::new(self.inner.clone(), &mut stream);
350351
Ok((
351352
StreamRef {
352353
opaque: OpaqueStreamRef::new(self.inner.clone(), &mut stream),
353354
send_buffer: self.send_buffer.clone(),
354355
},
356+
response,
355357
is_full,
356358
))
357359
}
@@ -1557,7 +1559,7 @@ impl OpaqueStreamRef {
15571559
}
15581560

15591561
pub fn stream_id(&self) -> StreamId {
1560-
self.inner.lock().unwrap().store[self.key].id
1562+
self.key.stream_id()
15611563
}
15621564
}
15631565

tests/h2-tests/tests/client_request.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use futures::future::{ready, Either};
1+
use futures::future::{poll_fn, ready, Either};
22
use futures::stream::FuturesUnordered;
33
use futures::StreamExt;
44
use h2_support::prelude::*;
@@ -47,12 +47,12 @@ async fn client_other_thread() {
4747
.uri("https://http2.akamai.com/")
4848
.body(())
4949
.unwrap();
50-
let _res = client
51-
.send_request(request, true)
52-
.unwrap()
53-
.0
50+
let mut response = client.send_request(request, true).unwrap().0;
51+
let stream_id = response.stream_id();
52+
let _res = poll_fn(|cx| Pin::new(&mut response).poll(cx))
5453
.await
5554
.expect("request");
55+
assert_eq!(response.stream_id(), stream_id);
5656
});
5757
h2.await.expect("h2");
5858
};

0 commit comments

Comments
 (0)