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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user