mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
feat(admin): make capacity calculation resilient when backend info is missing (#1560)
Signed-off-by: heihutu <30542132+heihutu@users.noreply.github.com> Signed-off-by: majinghe <42570491+majinghe@users.noreply.github.com> Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com> Co-authored-by: heihutu <30542132+heihutu@users.noreply.github.com>
This commit is contained in:
@@ -1384,28 +1384,109 @@ impl SetDisks {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_disk_online_state(state: &str) -> bool {
|
||||
// The disk state strings are produced from rustfs_utils::os::get_drive_stats or DiskError::to_string().
|
||||
// Conventionally, online is "ok"/"online" (may evolve). Be conservative:
|
||||
// - Treat empty as unknown -> include it (to avoid dropping capacity).
|
||||
// - Exclude explicit offline-ish states.
|
||||
let s = state.trim().to_lowercase();
|
||||
if s.is_empty() {
|
||||
return true;
|
||||
}
|
||||
if s.contains("offline") {
|
||||
return false;
|
||||
}
|
||||
if s.contains("not found") || s.contains("disk not found") {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn fallback_total_capacity(disks: &[rustfs_madmin::Disk]) -> usize {
|
||||
disks
|
||||
.iter()
|
||||
.filter(|d| is_disk_online_state(&d.state))
|
||||
.map(|d| d.total_space as usize)
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn fallback_free_capacity(disks: &[rustfs_madmin::Disk]) -> usize {
|
||||
disks
|
||||
.iter()
|
||||
.filter(|d| is_disk_online_state(&d.state))
|
||||
.map(|d| d.available_space as usize)
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn get_total_usable_capacity(disks: &[rustfs_madmin::Disk], info: &rustfs_madmin::StorageInfo) -> usize {
|
||||
let mut capacity = 0;
|
||||
// If backend info is missing or inconsistent, do a safe fallback to avoid reporting nonsense.
|
||||
if info.backend.standard_sc_data.is_empty() {
|
||||
return fallback_total_capacity(disks);
|
||||
}
|
||||
|
||||
let mut capacity = 0usize;
|
||||
let mut matched_any = false;
|
||||
|
||||
for disk in disks.iter() {
|
||||
if disk.pool_index < 0 || info.backend.standard_sc_data.len() <= disk.pool_index as usize {
|
||||
if disk.pool_index < 0 {
|
||||
continue;
|
||||
}
|
||||
if (disk.disk_index as usize) < info.backend.standard_sc_data[disk.pool_index as usize] {
|
||||
let pool_idx = disk.pool_index as usize;
|
||||
if info.backend.standard_sc_data.len() <= pool_idx {
|
||||
continue;
|
||||
}
|
||||
|
||||
let usable_disks_per_set = info.backend.standard_sc_data[pool_idx];
|
||||
if usable_disks_per_set == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disk.disk_index as usize) < usable_disks_per_set {
|
||||
matched_any = true;
|
||||
capacity += disk.total_space as usize;
|
||||
}
|
||||
}
|
||||
capacity
|
||||
|
||||
if matched_any {
|
||||
capacity
|
||||
} else {
|
||||
// Even if standard_sc_data exists, it might not match disk indexes due to upstream bugs.
|
||||
// Fallback to summing all online disks to prevent under-reporting.
|
||||
fallback_total_capacity(disks)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_total_usable_capacity_free(disks: &[rustfs_madmin::Disk], info: &rustfs_madmin::StorageInfo) -> usize {
|
||||
let mut capacity = 0;
|
||||
if info.backend.standard_sc_data.is_empty() {
|
||||
return fallback_free_capacity(disks);
|
||||
}
|
||||
|
||||
let mut capacity = 0usize;
|
||||
let mut matched_any = false;
|
||||
|
||||
for disk in disks.iter() {
|
||||
if disk.pool_index < 0 || info.backend.standard_sc_data.len() <= disk.pool_index as usize {
|
||||
if disk.pool_index < 0 {
|
||||
continue;
|
||||
}
|
||||
if (disk.disk_index as usize) < info.backend.standard_sc_data[disk.pool_index as usize] {
|
||||
let pool_idx = disk.pool_index as usize;
|
||||
if info.backend.standard_sc_data.len() <= pool_idx {
|
||||
continue;
|
||||
}
|
||||
|
||||
let usable_disks_per_set = info.backend.standard_sc_data[pool_idx];
|
||||
if usable_disks_per_set == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disk.disk_index as usize) < usable_disks_per_set {
|
||||
matched_any = true;
|
||||
capacity += disk.available_space as usize;
|
||||
}
|
||||
}
|
||||
capacity
|
||||
|
||||
if matched_any {
|
||||
capacity
|
||||
} else {
|
||||
fallback_free_capacity(disks)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6817,10 +6817,17 @@ async fn get_storage_info(disks: &[Option<DiskStore>], eps: &[Endpoint]) -> rust
|
||||
let mut disks = get_disks_info(disks, eps).await;
|
||||
disks.sort_by(|a, b| a.total_space.cmp(&b.total_space));
|
||||
|
||||
// Provide minimal backend shape for callers. Do NOT guess parity here since it belongs to higher-level config.
|
||||
// Missing/empty standard_sc_data will be handled by capacity fallback logic.
|
||||
let drives_per_set = vec![eps.len()];
|
||||
let total_sets = vec![1];
|
||||
|
||||
rustfs_madmin::StorageInfo {
|
||||
disks,
|
||||
backend: rustfs_madmin::BackendInfo {
|
||||
backend_type: rustfs_madmin::BackendByte::Erasure,
|
||||
drives_per_set,
|
||||
total_sets,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user