feat: enhance storage stats and cluster health reporting

- Introduced new data structures for bucket and storage statistics, including BucketSummary, StorageStats, and ClusterHealth.
- Implemented runtime statistics tracking for buckets, including object count and total size.
- Added methods to retrieve storage stats and bucket summaries in the FileStore.
- Enhanced the SmartStorage interface to expose storage stats and cluster health.
- Implemented tests for runtime stats, cluster health, and credential management.
- Added support for runtime-managed credentials with atomic replacement.
- Improved filesystem usage reporting for storage locations.
This commit is contained in:
2026-04-19 11:57:28 +00:00
parent c683b02e8c
commit 0e9862efca
16 changed files with 1803 additions and 85 deletions
+50 -6
View File
@@ -1,9 +1,9 @@
use super::config::DriveConfig;
use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tokio::fs;
use super::config::DriveConfig;
// ============================
// Drive format (on-disk metadata)
@@ -33,6 +33,7 @@ pub enum DriveStatus {
#[derive(Debug, Clone)]
pub struct DriveStats {
pub total_bytes: u64,
pub available_bytes: u64,
pub used_bytes: u64,
pub avg_write_latency_us: u64,
pub avg_read_latency_us: u64,
@@ -45,6 +46,7 @@ impl Default for DriveStats {
fn default() -> Self {
Self {
total_bytes: 0,
available_bytes: 0,
used_bytes: 0,
avg_write_latency_us: 0,
avg_read_latency_us: 0,
@@ -55,7 +57,7 @@ impl Default for DriveStats {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct DriveState {
pub path: PathBuf,
pub format: Option<DriveFormat>,
@@ -74,10 +76,15 @@ pub struct DriveManager {
impl DriveManager {
/// Initialize drive manager with configured drive paths.
pub async fn new(config: &DriveConfig) -> Result<Self> {
let mut drives = Vec::with_capacity(config.paths.len());
let paths: Vec<PathBuf> = config.paths.iter().map(PathBuf::from).collect();
Self::from_paths(&paths).await
}
for path_str in &config.paths {
let path = PathBuf::from(path_str);
/// Initialize drive manager from an explicit list of resolved paths.
pub async fn from_paths(paths: &[PathBuf]) -> Result<Self> {
let mut drives = Vec::with_capacity(paths.len());
for path in paths {
let storage_dir = path.join(".smartstorage");
// Ensure the drive directory exists
@@ -92,7 +99,7 @@ impl DriveManager {
};
drives.push(DriveState {
path,
path: path.clone(),
format,
status,
stats: DriveStats::default(),
@@ -154,6 +161,11 @@ impl DriveManager {
&self.drives
}
/// Get a cloneable snapshot of current drive states.
pub fn snapshot(&self) -> Vec<DriveState> {
self.drives.clone()
}
/// Get drives that are online.
pub fn online_drives(&self) -> Vec<usize> {
self.drives
@@ -203,6 +215,11 @@ impl DriveManager {
let _ = fs::remove_file(&probe_path).await;
let latency = start.elapsed();
if let Some((total_bytes, available_bytes, used_bytes)) = filesystem_usage(&drive.path) {
drive.stats.total_bytes = total_bytes;
drive.stats.available_bytes = available_bytes;
drive.stats.used_bytes = used_bytes;
}
drive.stats.avg_write_latency_us = latency.as_micros() as u64;
drive.stats.last_check = Utc::now();
@@ -240,3 +257,30 @@ impl DriveManager {
serde_json::from_str(&content).ok()
}
}
#[cfg(unix)]
fn filesystem_usage(path: &Path) -> Option<(u64, u64, u64)> {
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
let path_bytes = path.as_os_str().as_bytes();
let c_path = CString::new(path_bytes).ok()?;
let mut stat: libc::statvfs = unsafe { std::mem::zeroed() };
if unsafe { libc::statvfs(c_path.as_ptr(), &mut stat) } != 0 {
return None;
}
let block_size = stat.f_frsize as u64;
let total_bytes = stat.f_blocks as u64 * block_size;
let available_bytes = stat.f_bavail as u64 * block_size;
let free_bytes = stat.f_bfree as u64 * block_size;
let used_bytes = total_bytes.saturating_sub(free_bytes);
Some((total_bytes, available_bytes, used_bytes))
}
#[cfg(not(unix))]
fn filesystem_usage(_path: &Path) -> Option<(u64, u64, u64)> {
None
}