canic_core/ops/placement/sharding/
metrics.rs1use crate::ops::storage::sharding::ShardingRegistryOps;
2
3#[derive(Clone, Copy, Debug)]
9pub struct PoolMetrics {
10 pub utilization_pct: u32,
11 pub active_count: u32,
12 pub total_capacity: u64,
13 pub total_used: u64,
14}
15
16#[must_use]
18pub fn pool_metrics(pool: &str) -> PoolMetrics {
19 let view = ShardingRegistryOps::export();
20 let mut active = 0;
21 let mut cap = 0;
22 let mut used = 0;
23
24 for (_, e) in &view {
25 if e.capacity > 0 && e.pool.as_ref() == pool {
26 active += 1;
27 cap += u64::from(e.capacity);
28 used += u64::from(e.count);
29 }
30 }
31
32 let utilization = if cap == 0 {
33 0
34 } else {
35 ((used * 100) / cap).min(100) as u32
36 };
37
38 PoolMetrics {
39 utilization_pct: utilization,
40 active_count: active,
41 total_capacity: cap,
42 total_used: used,
43 }
44}
45
46#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::{
54 cdk::types::Principal, ids::CanisterRole, ops::storage::sharding::ShardingRegistryOps,
55 };
56
57 fn p(id: u8) -> Principal {
58 Principal::from_slice(&[id; 29])
59 }
60
61 #[test]
62 fn pool_metrics_computation() {
63 ShardingRegistryOps::clear_for_test();
64 ShardingRegistryOps::create(p(1), "poolA", 0, &CanisterRole::new("alpha"), 10).unwrap();
65 ShardingRegistryOps::create(p(2), "poolA", 1, &CanisterRole::new("alpha"), 20).unwrap();
66
67 ShardingRegistryOps::assign("poolA", "t1", p(1)).unwrap();
68 ShardingRegistryOps::assign("poolA", "t2", p(1)).unwrap();
69 ShardingRegistryOps::assign("poolA", "t3", p(2)).unwrap();
70 ShardingRegistryOps::assign("poolA", "t4", p(2)).unwrap();
71 ShardingRegistryOps::assign("poolA", "t5", p(2)).unwrap();
72
73 let m = pool_metrics("poolA");
74 assert_eq!(m.active_count, 2);
75 assert_eq!(m.total_capacity, 30);
76 assert_eq!(m.total_used, 5);
77 assert_eq!(m.utilization_pct, (5 * 100 / 30) as u32);
78 }
79}