Skip to content

Commit

Permalink
keepalive: add setting of interval between probes.
Browse files Browse the repository at this point in the history
  • Loading branch information
fulara committed Feb 17, 2022
1 parent 906d30d commit 39cbf2b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/conn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ impl Conn {
let write_timeout = opts.get_write_timeout().cloned();
let tcp_keepalive_time = opts.get_tcp_keepalive_time_ms();
#[cfg(any(target_os = "linux", target_os = "macos",))]
let tcp_keepalive_probe_interval_secs = opts.get_tcp_keepalive_probe_interval_secs();
#[cfg(any(target_os = "linux", target_os = "macos",))]
let tcp_keepalive_probe_count = opts.get_tcp_keepalive_probe_count();
#[cfg(target_os = "linux")]
let tcp_user_timeout = opts.get_tcp_user_timeout_ms();
Expand All @@ -414,6 +416,8 @@ impl Conn {
write_timeout,
tcp_keepalive_time,
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_interval_secs,
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_count,
#[cfg(target_os = "linux")]
tcp_user_timeout,
Expand Down
55 changes: 54 additions & 1 deletion src/conn/opts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ pub(crate) struct InnerOpts {
/// Can be defined using `tcp_keepalive_time_ms` connection url parameter.
tcp_keepalive_time: Option<u32>,

/// TCP keep alive interval between subsequent probe for mysql connection.
///
/// Can be defined using `tcp_keepalive_probe_interval_secs` connection url parameter.
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_interval_secs: Option<u32>,

/// TCP keep alive probe count for mysql connection.
///
/// Can be defined using `tcp_keepalive_probe_count` connection url parameter.
Expand Down Expand Up @@ -229,6 +235,8 @@ impl Default for InnerOpts {
ssl_opts: None,
tcp_keepalive_time: None,
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_interval_secs: None,
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_count: None,
#[cfg(target_os = "linux")]
tcp_user_timeout: None,
Expand Down Expand Up @@ -336,6 +344,12 @@ impl Opts {
self.0.tcp_keepalive_time
}

/// TCP keep alive interval between subsequent probes for mysql connection.
#[cfg(any(target_os = "linux", target_os = "macos",))]
pub fn get_tcp_keepalive_probe_interval_secs(&self) -> Option<u32> {
self.0.tcp_keepalive_probe_interval_secs
}

/// TCP keep alive probe count for mysql connection.
#[cfg(any(target_os = "linux", target_os = "macos",))]
pub fn get_tcp_keepalive_probe_count(&self) -> Option<u32> {
Expand Down Expand Up @@ -504,6 +518,7 @@ impl OptsBuilder {
/// - db_name = Database name (defaults to `None`).
/// - prefer_socket = Prefer socket connection (defaults to `true`)
/// - tcp_keepalive_time_ms = TCP keep alive time for mysql connection (defaults to `None`)
/// - tcp_keepalive_probe_interval_secs = TCP keep alive interval between probes for mysql connection (defaults to `None`)
/// - tcp_keepalive_probe_count = TCP keep alive probe count for mysql connection (defaults to `None`)
/// - tcp_user_timeout_ms = TCP_USER_TIMEOUT time for mysql connection (defaults to `None`)
/// - compress = Compression level(defaults to `None`)
Expand Down Expand Up @@ -557,6 +572,16 @@ impl OptsBuilder {
}
}
#[cfg(any(target_os = "linux", target_os = "macos",))]
"tcp_keepalive_probe_interval_secs" => {
//if cannot parse, default to none
self.opts.0.tcp_keepalive_probe_interval_secs = match value.parse::<u32>() {
Ok(val) => Some(val),
_ => {
return Err(UrlError::InvalidValue(key.to_string(), value.to_string()))
}
}
}
#[cfg(any(target_os = "linux", target_os = "macos",))]
"tcp_keepalive_probe_count" => {
//if cannot parse, default to none
self.opts.0.tcp_keepalive_probe_count = match value.parse::<u32>() {
Expand Down Expand Up @@ -686,6 +711,19 @@ impl OptsBuilder {
self
}

/// TCP keep alive interval between probes for mysql connection (defaults to `None`). Available as
/// `tcp_keepalive_probe_interval_secs` url parameter.
///
/// Can be defined using `tcp_keepalive_probe_interval_secs` connection url parameter.
#[cfg(any(target_os = "linux", target_os = "macos",))]
pub fn tcp_keepalive_probe_interval_secs(
mut self,
tcp_keepalive_probe_interval_secs: Option<u32>,
) -> Self {
self.opts.0.tcp_keepalive_probe_interval_secs = tcp_keepalive_probe_interval_secs;
self
}

/// TCP keep alive probe count for mysql connection (defaults to `None`). Available as
/// `tcp_keepalive_probe_count` url parameter.
///
Expand Down Expand Up @@ -991,6 +1029,11 @@ mod test {

#[test]
fn should_convert_url_into_opts() {
#[cfg(any(target_os = "linux", target_os = "macos",))]
let tcp_keepalive_probe_interval_secs = "&tcp_keepalive_probe_interval_secs=8";
#[cfg(not(any(target_os = "linux", target_os = "macos",)))]
let tcp_keepalive_probe_interval_secs = "";

#[cfg(any(target_os = "linux", target_os = "macos",))]
let tcp_keepalive_probe_count = "&tcp_keepalive_probe_count=5";
#[cfg(not(any(target_os = "linux", target_os = "macos",)))]
Expand All @@ -1002,7 +1045,8 @@ mod test {
let tcp_user_timeout = "";

let opts = format!(
"mysql://us%20r:p%20w@localhost:3308/db%2dname?prefer_socket=false&tcp_keepalive_time_ms=5000{}{}&socket=%2Ftmp%2Fmysql.sock&compress=8",
"mysql://us%20r:p%20w@localhost:3308/db%2dname?prefer_socket=false&tcp_keepalive_time_ms=5000{}{}{}&socket=%2Ftmp%2Fmysql.sock&compress=8",
tcp_keepalive_probe_interval_secs,
tcp_keepalive_probe_count,
tcp_user_timeout,
);
Expand All @@ -1016,6 +1060,8 @@ mod test {
prefer_socket: false,
tcp_keepalive_time: Some(5000),
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_interval_secs: Some(8),
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_count: Some(5),
#[cfg(target_os = "linux")]
tcp_user_timeout: Some(6000),
Expand Down Expand Up @@ -1072,6 +1118,8 @@ mod test {
"prefer_socket".to_string() => "false".to_string(),
"tcp_keepalive_time_ms".to_string() => "5000".to_string(),
#[cfg(any(target_os = "linux", target_os = "macos",))]
"tcp_keepalive_probe_interval_secs".to_string() => "8".to_string(),
#[cfg(any(target_os = "linux", target_os = "macos",))]
"tcp_keepalive_probe_count".to_string() => "5".to_string(),
"compress".to_string() => "best".to_string(),
"tcp_connect_timeout_ms".to_string() => "1000".to_string(),
Expand All @@ -1088,6 +1136,11 @@ mod test {
assert_eq!(parsed_opts.opts.get_prefer_socket(), false);
assert_eq!(parsed_opts.opts.get_tcp_keepalive_time_ms(), Some(5000));
#[cfg(any(target_os = "linux", target_os = "macos",))]
assert_eq!(
parsed_opts.opts.get_tcp_keepalive_probe_interval_secs(),
Some(8)
);
#[cfg(any(target_os = "linux", target_os = "macos",))]
assert_eq!(parsed_opts.opts.get_tcp_keepalive_probe_count(), Some(5));
assert_eq!(
parsed_opts.opts.get_compress(),
Expand Down
4 changes: 4 additions & 0 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl Stream {
read_timeout: Option<Duration>,
write_timeout: Option<Duration>,
tcp_keepalive_time: Option<u32>,
#[cfg(any(target_os = "linux", target_os = "macos",))]
tcp_keepalive_probe_interval_secs: Option<u32>,
#[cfg(any(target_os = "linux", target_os = "macos",))] tcp_keepalive_probe_count: Option<
u32,
>,
Expand All @@ -113,6 +115,8 @@ impl Stream {
.nodelay(nodelay)
.bind_address(bind_address);
#[cfg(any(target_os = "linux", target_os = "macos",))]
builder.keepalive_probe_interval_secs(tcp_keepalive_probe_interval_secs);
#[cfg(any(target_os = "linux", target_os = "macos",))]
builder.keepalive_probe_count(tcp_keepalive_probe_count);
#[cfg(target_os = "linux")]
builder.user_timeout(tcp_user_timeout);
Expand Down
32 changes: 32 additions & 0 deletions src/io/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct MyTcpBuilder<T> {
write_timeout: Option<Duration>,
keepalive_time_ms: Option<u32>,
#[cfg(any(target_os = "linux", target_os = "macos",))]
keepalive_probe_interval_secs: Option<u32>,
#[cfg(any(target_os = "linux", target_os = "macos",))]
keepalive_probe_count: Option<u32>,
#[cfg(target_os = "linux")]
user_timeout: Option<u32>,
Expand All @@ -34,6 +36,15 @@ impl<T: ToSocketAddrs> MyTcpBuilder<T> {
self
}

#[cfg(any(target_os = "linux", target_os = "macos",))]
pub fn keepalive_probe_interval_secs(
&mut self,
keepalive_probe_interval_secs: Option<u32>,
) -> &mut Self {
self.keepalive_probe_interval_secs = keepalive_probe_interval_secs;
self
}

#[cfg(any(target_os = "linux", target_os = "macos",))]
pub fn keepalive_probe_count(&mut self, keepalive_probe_count: Option<u32>) -> &mut Self {
self.keepalive_probe_count = keepalive_probe_count;
Expand Down Expand Up @@ -83,6 +94,8 @@ impl<T: ToSocketAddrs> MyTcpBuilder<T> {
write_timeout: None,
keepalive_time_ms: None,
#[cfg(any(target_os = "linux", target_os = "macos",))]
keepalive_probe_interval_secs: None,
#[cfg(any(target_os = "linux", target_os = "macos",))]
keepalive_probe_count: None,
#[cfg(target_os = "linux")]
user_timeout: None,
Expand All @@ -98,6 +111,8 @@ impl<T: ToSocketAddrs> MyTcpBuilder<T> {
read_timeout,
write_timeout,
keepalive_time_ms,
#[cfg(any(target_os = "linux", target_os = "macos"))]
keepalive_probe_interval_secs,
#[cfg(any(target_os = "linux", target_os = "macos",))]
keepalive_probe_count,
#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -170,6 +185,23 @@ impl<T: ToSocketAddrs> MyTcpBuilder<T> {
socket2::TcpKeepalive::new().with_time(Duration::from_millis(duration as u64));
socket.set_tcp_keepalive(&conf)?;
}
#[cfg(any(target_os = "linux", target_os = "macos",))]
if let Some(keepalive_probe_interval_secs) = keepalive_probe_interval_secs {
use std::os::unix::io::AsRawFd;
let fd = socket.as_raw_fd();
unsafe {
if libc::setsockopt(
fd,
libc::IPPROTO_TCP,
libc::TCP_KEEPINTVL,
&keepalive_probe_interval_secs as *const _ as *const libc::c_void,
std::mem::size_of_val(&keepalive_probe_interval_secs) as libc::socklen_t,
) != 0
{
return Err(io::Error::last_os_error());
}
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
if let Some(keepalive_probe_count) = keepalive_probe_count {
use std::os::unix::io::AsRawFd;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
//! * `prefer_socket: true | false` - defines the value of the same field in the `Opts` structure;
//! * `tcp_keepalive_time_ms: u32` - defines the value (in milliseconds)
//! of the `tcp_keepalive_time` field in the `Opts` structure;
//! * `tcp_keepalive_probe_interval_secs: u32` - defines the value
//! of the `tcp_keepalive_probe_interval_secs` field in the `Opts` structure;
//! * `tcp_keepalive_probe_count: u32` - defines the value
//! of the `tcp_keepalive_probe_count` field in the `Opts` structure;
//! * `tcp_connect_timeout_ms: u64` - defines the value (in milliseconds)
Expand Down

0 comments on commit 39cbf2b

Please sign in to comment.