diff --git a/Cargo.lock b/Cargo.lock index e7b114c9..f70921b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1901,7 +1901,7 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" dependencies = [ - "nix", + "nix 0.29.0", "winapi", ] @@ -2039,6 +2039,18 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -2351,7 +2363,7 @@ dependencies = [ [[package]] name = "pgdog" -version = "0.1.7" +version = "0.1.700" dependencies = [ "arc-swap", "async-trait", @@ -2370,8 +2382,10 @@ dependencies = [ "hyper-util", "indexmap", "lazy_static", + "libc", "lru 0.16.0", "md5", + "nix 0.30.1", "once_cell", "parking_lot", "pg_query", @@ -3948,7 +3962,7 @@ dependencies = [ "libc", "log", "memmem", - "nix", + "nix 0.29.0", "num-derive", "num-traits", "ordered-float", diff --git a/pgdog/Cargo.toml b/pgdog/Cargo.toml index 43c22272..d3a1120a 100644 --- a/pgdog/Cargo.toml +++ b/pgdog/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pgdog" -version = "0.1.7" +version = "0.1.700" edition = "2021" description = "Modern PostgreSQL proxy, pooler and load balancer." authors = ["Lev Kokotov "] @@ -23,6 +23,8 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "std"] } parking_lot = "0.12" thiserror = "2" +libc = "0.2" +nix = {version = "0.30.1", features = ["process"]} bytes = "1" clap = { version = "4", features = ["derive"] } serde = { version = "1", features = ["derive"] } diff --git a/pgdog/src/frontend/listener.rs b/pgdog/src/frontend/listener.rs index f4ceabf7..f21a4809 100644 --- a/pgdog/src/frontend/listener.rs +++ b/pgdog/src/frontend/listener.rs @@ -1,9 +1,4 @@ //! Connection listener. Handles all client connections. - -use std::io::ErrorKind; -use std::net::SocketAddr; -use std::sync::Arc; - use crate::backend::databases::{databases, reload, shutdown}; use crate::config::config; use crate::frontend::client::query_engine::two_pc::Manager; @@ -12,12 +7,18 @@ use crate::net::messages::{hello::SslReply, Startup}; use crate::net::{self, tls::acceptor}; use crate::net::{tweak, Stream}; use crate::sighup::Sighup; +use crate::sigusr::Sigusr; +use nix::unistd::execv; +use std::env::current_exe; +use std::ffi::CString; +use std::io::ErrorKind; +use std::net::SocketAddr; +use std::sync::Arc; use tokio::net::{TcpListener, TcpStream}; use tokio::signal::ctrl_c; use tokio::sync::Notify; use tokio::time::timeout; use tokio::{select, spawn}; - use tracing::{error, info, warn}; use super::{ @@ -42,16 +43,17 @@ impl Listener { } /// Listen for client connections and handle them. + #[allow(unreachable_code)] pub async fn listen(&mut self) -> Result<(), Error> { info!("🐕 PgDog listening on {}", self.addr); let listener = TcpListener::bind(&self.addr).await?; let comms = comms(); let shutdown_signal = comms.shutting_down(); let mut sighup = Sighup::new()?; + let mut sigusr = Sigusr::new()?; loop { let comms = comms.clone(); - select! { connection = listener.accept() => { let (stream, addr) = connection?; @@ -82,6 +84,23 @@ impl Listener { self.start_shutdown(); } + _ = sigusr.listen() => + { + info!("Hot-patching signal received"); + match current_exe() + { + Ok(path) => { + info!("Hot-loading from {}",path.display()); + let program = CString::new(path.into_os_string().into_encoded_bytes()).unwrap(); + let args: Vec = vec![]; + execv(&program, &args).expect("execv failed"); + } + Err(e) => { + error!("Failed to get executable path: {}", e); + } + } + } + _ = sighup.listen() => { if let Err(err) = reload() { error!("configuration reload error: {}", err); @@ -96,7 +115,6 @@ impl Listener { Ok(()) } - /// Shutdown this listener. pub fn shutdown(&self) { self.shutdown.notify_one(); diff --git a/pgdog/src/lib.rs b/pgdog/src/lib.rs index 2a252d30..bda709d1 100644 --- a/pgdog/src/lib.rs +++ b/pgdog/src/lib.rs @@ -12,6 +12,7 @@ pub mod healthcheck; pub mod net; pub mod plugin; pub mod sighup; +pub mod sigusr; pub mod state; pub mod stats; #[cfg(feature = "tui")] diff --git a/pgdog/src/sigusr.rs b/pgdog/src/sigusr.rs new file mode 100644 index 00000000..909100b2 --- /dev/null +++ b/pgdog/src/sigusr.rs @@ -0,0 +1,33 @@ +#[cfg(target_family = "unix")] +use tokio::signal::unix::*; + +pub struct Sigusr { + #[cfg(target_family = "unix")] + sig: Signal, +} + +impl Sigusr { + #[cfg(target_family = "unix")] + pub(crate) fn new() -> std::io::Result { + let sig = signal(SignalKind::user_defined1())?; + Ok(Self { sig }) + } + + #[cfg(not(target_family = "unix"))] + pub(crate) fn new() -> std::io::Result { + Self {} + } + + pub(crate) async fn listen(&mut self) { + #[cfg(target_family = "unix")] + self.sig.recv().await; + + #[cfg(not(target_family = "unix"))] + loop { + use std::time::Duration; + use tokio::time::sleep; + + sleep(Duration::MAX).await; + } + } +}