diff --git a/Cargo.lock b/Cargo.lock index 5b00a313..0c1890c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,6 +726,7 @@ dependencies = [ "image", "ipaddress", "itertools 0.13.0", + "libc", "libloading", "log", "nix", @@ -739,7 +740,6 @@ dependencies = [ "serde_json", "serde_regex", "serde_yaml", - "sysinfo", "thiserror 2.0.7", "tikv-jemalloc-ctl", "tikv-jemalloc-sys", @@ -1674,7 +1674,7 @@ checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" dependencies = [ "cfg-if", "libc", - "windows 0.52.0", + "windows", ] [[package]] @@ -4076,18 +4076,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "sysinfo" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46" -dependencies = [ - "core-foundation-sys", - "libc", - "serde", - "windows 0.57.0", -] - [[package]] name = "tendril" version = "0.4.3" @@ -4945,17 +4933,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", + "windows-core", "windows-targets 0.52.6", ] @@ -4968,60 +4946,17 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-strings", "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.2.0" @@ -5037,7 +4972,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] diff --git a/Cargo.toml b/Cargo.toml index 24e6eb79..022baaa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -498,10 +498,8 @@ version = "1.3.0" [workspace.dependencies.core_affinity] version = "0.8.1" -[workspace.dependencies.sysinfo] -version = "0.33.0" -default-features = false -features = ["disk", "serde"] +[workspace.dependencies.libc] +version = "0.2" # # Patches diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index d249f647..2873a05d 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -75,6 +75,7 @@ http.workspace = true image.workspace = true ipaddress.workspace = true itertools.workspace = true +libc.workspace = true libloading.workspace = true log.workspace = true rand.workspace = true @@ -87,7 +88,6 @@ serde_json.workspace = true serde_regex.workspace = true serde_yaml.workspace = true serde.workspace = true -sysinfo.workspace = true thiserror.workspace = true tikv-jemallocator.optional = true tikv-jemallocator.workspace = true diff --git a/src/core/utils/sys/storage.rs b/src/core/utils/sys/storage.rs index 8dc75236..25b17904 100644 --- a/src/core/utils/sys/storage.rs +++ b/src/core/utils/sys/storage.rs @@ -1,14 +1,20 @@ //! System utilities related to devices/peripherals use std::{ - ffi::{OsStr, OsString}, + ffi::OsStr, fs, fs::{read_to_string, FileType}, iter::IntoIterator, - path::Path, + path::{Path, PathBuf}, }; -use crate::{result::FlatOk, Result}; +use libc::dev_t; + +use crate::{ + result::FlatOk, + utils::{result::LogDebugErr, string::SplitInfallible}, + Result, +}; /// Device characteristics useful for random access throughput #[derive(Clone, Debug, Default)] @@ -35,16 +41,12 @@ pub struct Queue { /// Get device characteristics useful for random access throughput by name. #[must_use] -pub fn parallelism(name: &OsStr) -> Parallelism { - let name = name - .to_str() - .expect("device name expected to be utf-8 representable"); +pub fn parallelism(path: &Path) -> Parallelism { + let dev_id = dev_from_path(path).log_debug_err().unwrap_or_default(); - let block_path = Path::new("/").join("sys/").join("block/"); + let mq_path = block_path(dev_id).join("mq/"); - let mq_path = Path::new(&block_path).join(format!("{name}/mq/")); - - let nr_requests_path = Path::new(&block_path).join(format!("{name}/queue/nr_requests")); + let nr_requests_path = block_path(dev_id).join("queue/nr_requests"); Parallelism { nr_requests: read_to_string(&nr_requests_path) @@ -96,17 +98,39 @@ fn queue_parallelism(dir: &Path) -> Queue { } } -/// Get the name of the device on which Path is mounted. -#[must_use] -pub fn name_from_path(path: &Path) -> Option { - sysinfo::Disks::new_with_refreshed_list() - .into_iter() - .filter(|disk| path.starts_with(disk.mount_point())) - .max_by(|a, b| { - let a = a.mount_point().ancestors().count(); - let b = b.mount_point().ancestors().count(); - a.cmp(&b) - }) - .map(|disk| Path::new(disk.name())) - .and_then(|path| path.file_name().map(ToOwned::to_owned)) +/// Get the name of the block device on which Path is mounted. +pub fn name_from_path(path: &Path) -> Result { + use std::io::{Error, ErrorKind::NotFound}; + + let (major, minor) = dev_from_path(path)?; + let path = block_path((major, minor)).join("uevent"); + read_to_string(path) + .iter() + .map(String::as_str) + .flat_map(str::lines) + .map(|line| line.split_once_infallible("=")) + .find_map(|(key, val)| (key == "DEVNAME").then_some(val)) + .ok_or_else(|| Error::new(NotFound, "DEVNAME not found.")) + .map_err(Into::into) + .map(Into::into) +} + +/// Get the (major, minor) of the block device on which Path is mounted. +#[allow(clippy::useless_conversion, clippy::unnecessary_fallible_conversions)] +pub fn dev_from_path(path: &Path) -> Result<(dev_t, dev_t)> { + #[cfg(target_family = "unix")] + use std::os::unix::fs::MetadataExt; + + let stat = fs::metadata(path)?; + let dev_id = stat.dev().try_into()?; + + // SAFETY: These functions may not need to be marked as unsafe. + // see: https://github.com/rust-lang/libc/issues/3759 + let (major, minor) = unsafe { (libc::major(dev_id), libc::minor(dev_id)) }; + + Ok((major.try_into()?, minor.try_into()?)) +} + +fn block_path((major, minor): (dev_t, dev_t)) -> PathBuf { + format!("/sys/dev/block/{major}:{minor}/").into() } diff --git a/src/database/pool/configure.rs b/src/database/pool/configure.rs index 9361a534..2a192a9c 100644 --- a/src/database/pool/configure.rs +++ b/src/database/pool/configure.rs @@ -1,9 +1,10 @@ -use std::{ffi::OsStr, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; use conduwuit::{ debug, debug_info, expected, utils::{ math::usize_from_f64, + result::LogDebugErr, stream, stream::WIDTH_LIMIT, sys::{compute::is_core_available, storage}, @@ -20,8 +21,12 @@ pub(super) fn configure(server: &Arc) -> (usize, Vec, Vec) // This finds the block device and gathers all the properties we need. let (device_name, device_prop) = config .db_pool_affinity - .and_then(|| storage::name_from_path(&config.database_path)) - .map(|device_name| (device_name.clone(), storage::parallelism(&device_name))) + .and_then(|| { + let path: PathBuf = config.database_path.clone(); + let name = storage::name_from_path(&path).log_debug_err().ok(); + let prop = storage::parallelism(&path); + name.map(|name| (name, prop)) + }) .unzip(); // The default worker count is masked-on if we didn't find better information. @@ -104,7 +109,6 @@ pub(super) fn configure(server: &Arc) -> (usize, Vec, Vec) debug_info!( device_name = ?device_name .as_deref() - .and_then(OsStr::to_str) .unwrap_or("None"), ?worker_counts, ?queue_sizes,