diff --git a/Cargo.lock b/Cargo.lock index a3f3673636..c976cbb117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,6 +275,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "boxfnonce" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426" + [[package]] name = "bumpalo" version = "3.6.1" @@ -429,6 +435,16 @@ dependencies = [ "syn", ] +[[package]] +name = "daemonize" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70c24513e34f53b640819f0ac9f705b673fcf4006d7aab8778bee72ebfc89815" +dependencies = [ + "boxfnonce", + "libc", +] + [[package]] name = "digest" version = "0.9.0" @@ -1120,6 +1136,7 @@ dependencies = [ "chrono", "clap", "crossbeam-channel", + "daemonize", "futures", "lazy_static", "log", diff --git a/Cargo.toml b/Cargo.toml index f4d02d2625..199a6e3e92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ log = "0.4.14" clap = "2.33.0" termion = "1.5.6" tui = "0.14.0" - +daemonize = "0.4.1" rust-s3 = { git = "https://github.com/hlinnaka/rust-s3", features = ["no-verify-ssl"] } tokio = { version = "1.3.0", features = ["full"] } tokio-stream = { version = "0.1.4" } diff --git a/src/bin/pageserver.rs b/src/bin/pageserver.rs index f5f80e856a..94e5df7784 100644 --- a/src/bin/pageserver.rs +++ b/src/bin/pageserver.rs @@ -3,10 +3,13 @@ // use log::*; -use std::io::Error; +use std::fs::File; +use std::io; +use std::path::PathBuf; use std::{net::IpAddr, thread}; use clap::{App, Arg}; +use daemonize::Daemonize; use slog; use slog_stdlog; @@ -20,7 +23,7 @@ use pageserver::walreceiver; use pageserver::walredo; use pageserver::PageServerConf; -fn main() -> Result<(), Error> { +fn main() -> Result<(), io::Error> { let arg_matches = App::new("Zenith page server") .about("Materializes WAL stream to pages and serves them to the postgres") .arg(Arg::with_name("datadir") @@ -50,7 +53,7 @@ fn main() -> Result<(), Error> { .get_matches(); let mut conf = PageServerConf { - data_dir: String::from("."), + data_dir: PathBuf::from("./"), daemonize: false, interactive: false, wal_producer_ip: "127.0.0.1".parse::().unwrap(), @@ -59,7 +62,7 @@ fn main() -> Result<(), Error> { }; if let Some(dir) = arg_matches.value_of("datadir") { - conf.data_dir = String::from(dir); + conf.data_dir = PathBuf::from(dir); } if arg_matches.is_present("daemonize") { @@ -70,6 +73,13 @@ fn main() -> Result<(), Error> { conf.interactive = true; } + if conf.daemonize && conf.interactive { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "--daemonize is not allowed with --interactive: choose one", + )); + } + if arg_matches.is_present("skip_recovery") { conf.skip_recovery = true; } @@ -83,9 +93,7 @@ fn main() -> Result<(), Error> { start_pageserver(conf) } -fn start_pageserver(conf: PageServerConf) -> Result<(), Error> { - let mut threads = Vec::new(); - +fn start_pageserver(conf: PageServerConf) -> Result<(), io::Error> { // Initialize logger let _scope_guard; if !conf.interactive { @@ -111,6 +119,26 @@ fn start_pageserver(conf: PageServerConf) -> Result<(), Error> { tui_thread = None; } + if conf.daemonize { + info!("daemonizing..."); + + let stdout = File::create(conf.data_dir.join("pageserver.log")).unwrap(); + let stderr = File::create(conf.data_dir.join("pageserver.err.log")).unwrap(); + + let daemonize = Daemonize::new() + .pid_file(conf.data_dir.join("pageserver.pid")) + .working_directory(conf.data_dir.clone()) + .stdout(stdout) + .stderr(stderr); + + match daemonize.start() { + Ok(_) => info!("Success, daemonized"), + Err(e) => error!("Error, {}", e), + } + } + + let mut threads = Vec::new(); + info!("starting..."); // Initialize the WAL applicator diff --git a/src/lib.rs b/src/lib.rs index 7fd0f63de6..1dfc13f74d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ use std::net::IpAddr; +use std::path::PathBuf; #[allow(dead_code)] pub mod control_plane; @@ -13,8 +14,9 @@ pub mod tui; pub mod tui_event; mod tui_logger; +#[allow(dead_code)] pub struct PageServerConf { - pub data_dir: String, + pub data_dir: PathBuf, pub daemonize: bool, pub interactive: bool, pub wal_producer_ip: IpAddr,