diff --git a/kaspad/src/daemon.rs b/kaspad/src/daemon.rs index 26d8442b4..3dbaff978 100644 --- a/kaspad/src/daemon.rs +++ b/kaspad/src/daemon.rs @@ -30,6 +30,15 @@ use kaspa_perf_monitor::builder::Builder as PerfMonitorBuilder; use kaspa_utxoindex::{api::UtxoIndexProxy, UtxoIndex}; use kaspa_wrpc_server::service::{Options as WrpcServerOptions, ServerCounters as WrpcServerCounters, WrpcEncoding, WrpcService}; +/// Desired soft FD limit that needs to be configured +/// for the kaspad process. +pub const DESIRED_DAEMON_SOFT_FD_LIMIT: u64 = 16 * 1024; +/// Minimum acceptable soft FD limit for the kaspad +/// process. (Rusty Kaspa will operate with the minimal +/// acceptable limit of `4096`, but a setting below +/// this value may impact the database performance). +pub const MINIMUM_DAEMON_SOFT_FD_LIMIT: u64 = 4 * 1024; + use crate::args::Args; const DEFAULT_DATA_DIR: &str = "datadir"; diff --git a/kaspad/src/main.rs b/kaspad/src/main.rs index e7cdc94c0..04b2d2b11 100644 --- a/kaspad/src/main.rs +++ b/kaspad/src/main.rs @@ -6,7 +6,10 @@ use std::sync::Arc; use kaspa_core::{info, signals::Signals}; use kaspa_utils::fd_budget; -use kaspad_lib::{args::parse_args, daemon::create_core}; +use kaspad_lib::{ + args::parse_args, + daemon::{create_core, DESIRED_DAEMON_SOFT_FD_LIMIT, MINIMUM_DAEMON_SOFT_FD_LIMIT}, +}; #[cfg(feature = "heap")] #[global_allocator] @@ -17,6 +20,22 @@ pub fn main() { let _profiler = dhat::Profiler::builder().file_name("kaspad-heap.json").build(); let args = parse_args(); + + match fd_budget::try_set_fd_limit(DESIRED_DAEMON_SOFT_FD_LIMIT) { + Ok(limit) => { + if limit < MINIMUM_DAEMON_SOFT_FD_LIMIT { + println!("Current OS file descriptor limit (soft FD limit) is set to {limit}"); + println!("The kaspad node requires a setting of at least {DESIRED_DAEMON_SOFT_FD_LIMIT} to operate properly."); + println!("Please increase the limits using the following command:"); + println!("ulimit -n {DESIRED_DAEMON_SOFT_FD_LIMIT}"); + } + } + Err(err) => { + println!("Unable to initialize the necessary OS file descriptor limit (soft FD limit) to: {}", err); + println!("The kaspad node requires a setting of at least {DESIRED_DAEMON_SOFT_FD_LIMIT} to operate properly."); + } + } + let fd_total_budget = fd_budget::limit() - args.rpc_max_clients as i32 - args.inbound_limit as i32 - args.outbound_target as i32; let (core, _) = create_core(args, fd_total_budget); diff --git a/utils/src/fd_budget.rs b/utils/src/fd_budget.rs index b853ffb28..b9b6e811d 100644 --- a/utils/src/fd_budget.rs +++ b/utils/src/fd_budget.rs @@ -50,6 +50,17 @@ pub fn acquire_guard(value: i32) -> Result { } } +#[cfg(not(target_arch = "wasm32"))] +pub fn try_set_fd_limit(limit: u64) -> std::io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "windows")] { + Ok(rlimit::setmaxstdio(limit as u32)?.map(|v| v as u64)) + } else if #[cfg(unix)] { + rlimit::increase_nofile_limit(limit) + } + } +} + pub fn limit() -> i32 { cfg_if::cfg_if! { if #[cfg(test)] { @@ -58,7 +69,7 @@ pub fn limit() -> i32 { else if #[cfg(target_os = "windows")] { rlimit::getmaxstdio() as i32 } - else if #[cfg(any(target_os = "macos", target_os = "linux"))] { + else if #[cfg(unix)] { rlimit::getrlimit(rlimit::Resource::NOFILE).unwrap().0 as i32 } else {