From f3949a34894602faca39da71a1d6e82c5103aeec Mon Sep 17 00:00:00 2001 From: Stanislav Shmarov Date: Fri, 18 Sep 2020 12:31:54 +0300 Subject: [PATCH] feat(lib): Add a way to force queued strategy (#2282) --- src/client/conn.rs | 14 +++++++++----- src/client/mod.rs | 6 +++++- src/proto/h1/conn.rs | 4 ++++ src/proto/h1/io.rs | 7 +++++++ src/server/conn.rs | 20 ++++++++++++++------ src/server/mod.rs | 6 +++++- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/client/conn.rs b/src/client/conn.rs index 2383d5c907..48d5dfade3 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -75,7 +75,7 @@ where #[derive(Clone, Debug)] pub struct Builder { pub(super) exec: Exec, - h1_writev: bool, + h1_writev: Option, h1_title_case_headers: bool, h1_read_buf_exact_size: Option, h1_max_buf_size: Option, @@ -424,7 +424,7 @@ impl Builder { pub fn new() -> Builder { Builder { exec: Exec::Default, - h1_writev: true, + h1_writev: None, h1_read_buf_exact_size: None, h1_title_case_headers: false, h1_max_buf_size: None, @@ -443,7 +443,7 @@ impl Builder { } pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder { - self.h1_writev = enabled; + self.h1_writev = Some(enabled); self } @@ -609,8 +609,12 @@ impl Builder { let (tx, rx) = dispatch::channel(); let proto = if !opts.http2 { let mut conn = proto::Conn::new(io); - if !opts.h1_writev { - conn.set_write_strategy_flatten(); + if let Some(writev) = opts.h1_writev { + if writev { + conn.set_write_strategy_queue(); + } else { + conn.set_write_strategy_flatten(); + } } if opts.h1_title_case_headers { conn.set_title_case_headers(); diff --git a/src/client/mod.rs b/src/client/mod.rs index b4105bcb3c..1a5ed0f490 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -964,7 +964,11 @@ impl Builder { /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// - /// Default is `true`. + /// Setting this to true will force hyper to use queued strategy + /// which may eliminate unnecessary cloning on some TLS backends + /// + /// Default is `auto`. In this mode hyper will try to guess which + /// mode to use pub fn http1_writev(&mut self, val: bool) -> &mut Self { self.conn_builder.h1_writev(val); self diff --git a/src/proto/h1/conn.rs b/src/proto/h1/conn.rs index 5a3ed70742..f16d7d99e4 100644 --- a/src/proto/h1/conn.rs +++ b/src/proto/h1/conn.rs @@ -73,6 +73,10 @@ where self.io.set_write_strategy_flatten(); } + pub fn set_write_strategy_queue(&mut self) { + self.io.set_write_strategy_queue(); + } + pub fn set_title_case_headers(&mut self) { self.state.title_case_headers = true; } diff --git a/src/proto/h1/io.rs b/src/proto/h1/io.rs index e68abbb166..ed1b731306 100644 --- a/src/proto/h1/io.rs +++ b/src/proto/h1/io.rs @@ -94,6 +94,13 @@ where self.write_buf.set_strategy(WriteStrategy::Flatten); } + pub fn set_write_strategy_queue(&mut self) { + // this should always be called only at construction time, + // so this assert is here to catch myself + debug_assert!(self.write_buf.queue.bufs_cnt() == 0); + self.write_buf.set_strategy(WriteStrategy::Queue); + } + pub fn read_buf(&self) -> &[u8] { self.read_buf.as_ref() } diff --git a/src/server/conn.rs b/src/server/conn.rs index 9704899c5f..56fe4c58ec 100644 --- a/src/server/conn.rs +++ b/src/server/conn.rs @@ -81,7 +81,7 @@ pub struct Http { exec: E, h1_half_close: bool, h1_keep_alive: bool, - h1_writev: bool, + h1_writev: Option, h2_builder: proto::h2::server::Config, mode: ConnectionMode, max_buf_size: Option, @@ -217,7 +217,7 @@ impl Http { exec: Exec::Default, h1_half_close: false, h1_keep_alive: true, - h1_writev: true, + h1_writev: None, h2_builder: Default::default(), mode: ConnectionMode::Fallback, max_buf_size: None, @@ -274,10 +274,14 @@ impl Http { /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// - /// Default is `true`. + /// Setting this to true will force hyper to use queued strategy + /// which may eliminate unnecessary cloning on some TLS backends + /// + /// Default is `auto`. In this mode hyper will try to guess which + /// mode to use #[inline] pub fn http1_writev(&mut self, val: bool) -> &mut Self { - self.h1_writev = val; + self.h1_writev = Some(val); self } @@ -487,8 +491,12 @@ impl Http { if self.h1_half_close { conn.set_allow_half_close(); } - if !self.h1_writev { - conn.set_write_strategy_flatten(); + if let Some(writev) = self.h1_writev { + if writev { + conn.set_write_strategy_queue(); + } else { + conn.set_write_strategy_flatten(); + } } conn.set_flush_pipeline(self.pipeline_flush); if let Some(max) = self.max_buf_size { diff --git a/src/server/mod.rs b/src/server/mod.rs index 0a00dae54d..63bf2988ad 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -286,7 +286,11 @@ impl Builder { /// but may also improve performance when an IO transport doesn't /// support vectored writes well, such as most TLS implementations. /// - /// Default is `true`. + /// Setting this to true will force hyper to use queued strategy + /// which may eliminate unnecessary cloning on some TLS backends + /// + /// Default is `auto`. In this mode hyper will try to guess which + /// mode to use pub fn http1_writev(mut self, val: bool) -> Self { self.protocol.http1_writev(val); self