Skip to content

Commit

Permalink
perf: optimize header list size calculations (#750)
Browse files Browse the repository at this point in the history
This speeds up loading blocks in cases where we have many headers already.
  • Loading branch information
Noah-Kennedy committed Feb 22, 2024
1 parent 7243ab5 commit 94e80b1
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
1 change: 0 additions & 1 deletion .github/workflows/CI.yml
Expand Up @@ -31,7 +31,6 @@ jobs:
strategy:
matrix:
rust:
- nightly
- beta
- stable
steps:
Expand Down
23 changes: 18 additions & 5 deletions src/frame/headers.rs
Expand Up @@ -12,6 +12,7 @@ use std::fmt;
use std::io::Cursor;

type EncodeBuf<'a> = bytes::buf::Limit<&'a mut BytesMut>;

/// Header frame
///
/// This could be either a request or a response.
Expand Down Expand Up @@ -87,6 +88,9 @@ struct HeaderBlock {
/// The decoded header fields
fields: HeaderMap,

/// Precomputed size of all of our header fields, for perf reasons
field_size: usize,

/// Set to true if decoding went over the max header list size.
is_over_size: bool,

Expand Down Expand Up @@ -115,6 +119,7 @@ impl Headers {
stream_id,
stream_dep: None,
header_block: HeaderBlock {
field_size: calculate_headermap_size(&fields),
fields,
is_over_size: false,
pseudo,
Expand All @@ -131,6 +136,7 @@ impl Headers {
stream_id,
stream_dep: None,
header_block: HeaderBlock {
field_size: calculate_headermap_size(&fields),
fields,
is_over_size: false,
pseudo: Pseudo::default(),
Expand Down Expand Up @@ -196,6 +202,7 @@ impl Headers {
stream_dep,
header_block: HeaderBlock {
fields: HeaderMap::new(),
field_size: 0,
is_over_size: false,
pseudo: Pseudo::default(),
},
Expand Down Expand Up @@ -350,6 +357,7 @@ impl PushPromise {
PushPromise {
flags: PushPromiseFlag::default(),
header_block: HeaderBlock {
field_size: calculate_headermap_size(&fields),
fields,
is_over_size: false,
pseudo,
Expand Down Expand Up @@ -441,6 +449,7 @@ impl PushPromise {
flags,
header_block: HeaderBlock {
fields: HeaderMap::new(),
field_size: 0,
is_over_size: false,
pseudo: Pseudo::default(),
},
Expand Down Expand Up @@ -892,6 +901,8 @@ impl HeaderBlock {

headers_size += decoded_header_size(name.as_str().len(), value.len());
if headers_size < max_header_list_size {
self.field_size +=
decoded_header_size(name.as_str().len(), value.len());
self.fields.append(name, value);
} else if !self.is_over_size {
tracing::trace!("load_hpack; header list size over max");
Expand Down Expand Up @@ -958,14 +969,16 @@ impl HeaderBlock {
+ pseudo_size!(status)
+ pseudo_size!(authority)
+ pseudo_size!(path)
+ self
.fields
.iter()
.map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
.sum::<usize>()
+ self.field_size
}
}

fn calculate_headermap_size(map: &HeaderMap) -> usize {
map.iter()
.map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
.sum::<usize>()
}

fn decoded_header_size(name: usize, value: usize) -> usize {
name + value + 32
}
Expand Down
1 change: 1 addition & 0 deletions src/proto/streams/store.rs
Expand Up @@ -127,6 +127,7 @@ impl Store {
}
}

#[allow(clippy::blocks_in_conditions)]
pub(crate) fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(Ptr),
Expand Down

0 comments on commit 94e80b1

Please sign in to comment.