admin api: don't gather all bucket statistics if too many buckets

This commit is contained in:
Alex Auvolat
2026-03-10 11:35:35 +01:00
committed by Alex
parent 4566020360
commit 6131318c80
+48 -30
View File
@@ -173,31 +173,47 @@ impl RequestHandler for GetClusterStatisticsRequest {
) )
.await?; .await?;
let bucket_stats = futures::future::try_join_all( let bucket_stats_opt = if buckets.len() < 1000 {
buckets Some(
.iter() futures::future::try_join_all(
.map(|b| garage.object_counter_table.table.get(&b.id, &EmptyKey)), buckets
) .iter()
.await?; .map(|b| garage.object_counter_table.table.get(&b.id, &EmptyKey)),
)
.await?,
)
} else {
None
};
let layout = &garage.system.cluster_layout(); let layout = &garage.system.cluster_layout();
let bucket_stats = bucket_stats
.into_iter()
.filter_map(|cnt| cnt.map(|x| x.filtered_values(layout)))
.collect::<Vec<_>>();
let bucket_count = buckets.len() as u64; let bucket_count = buckets.len() as u64;
let total_object_count = bucket_stats let (total_object_count, total_object_bytes);
.iter() if let Some(bucket_stats) = bucket_stats_opt {
.clone() let bucket_stats = bucket_stats
.map(|cnt| *cnt.get(object_table::OBJECTS).unwrap_or(&0) as u64) .into_iter()
.sum(); .filter_map(|cnt| cnt.map(|x| x.filtered_values(layout)))
let total_object_bytes = bucket_stats .collect::<Vec<_>>();
.iter()
.clone() total_object_count = Some(
.map(|cnt| *cnt.get(object_table::BYTES).unwrap_or(&0) as u64) bucket_stats
.sum(); .iter()
.clone()
.map(|cnt| *cnt.get(object_table::OBJECTS).unwrap_or(&0) as u64)
.sum(),
);
total_object_bytes = Some(
bucket_stats
.iter()
.clone()
.map(|cnt| *cnt.get(object_table::BYTES).unwrap_or(&0) as u64)
.sum(),
);
} else {
total_object_count = None;
total_object_bytes = None;
}
// Gather storage node and free space statistics for current nodes // Gather storage node and free space statistics for current nodes
let mut node_partition_count = HashMap::<Uuid, u64>::new(); let mut node_partition_count = HashMap::<Uuid, u64>::new();
@@ -281,14 +297,16 @@ impl RequestHandler for GetClusterStatisticsRequest {
|| data_part_avail.len() < node_partition_count.len(); || data_part_avail.len() < node_partition_count.len();
// Display bucket statistics // Display bucket statistics
let bucket_stats = vec![ let mut bucket_stats = vec![format!("Number of buckets:\t{}", bucket_count)];
format!("Number of buckets:\t{}", bucket_count), if let Some(toc) = total_object_count {
format!("Total number of objects:\t{}", total_object_count), bucket_stats.push(format!("Total number of objects:\t{}", toc));
format!( }
if let Some(tob) = total_object_bytes {
bucket_stats.push(format!(
"Total size of objects:\t{}", "Total size of objects:\t{}",
bytesize::ByteSize(total_object_bytes) bytesize::ByteSize(tob)
), ));
]; }
writeln!(&mut ret, "\n{}", format_table_to_string(bucket_stats)).unwrap(); writeln!(&mut ret, "\n{}", format_table_to_string(bucket_stats)).unwrap();
writeln!( writeln!(
@@ -315,8 +333,8 @@ impl RequestHandler for GetClusterStatisticsRequest {
data_avail: Some(data_avail), data_avail: Some(data_avail),
incomplete_avail_info: Some(incomplete_info), incomplete_avail_info: Some(incomplete_info),
bucket_count: Some(bucket_count), bucket_count: Some(bucket_count),
total_object_count: Some(total_object_count), total_object_count,
total_object_bytes: Some(total_object_bytes), total_object_bytes,
}) })
} }
} }