canic_core/ops/placement/sharding/
metrics.rs

1use crate::ops::storage::sharding::ShardingRegistryOps;
2
3///
4/// PoolMetrics
5/// Aggregated metrics for a pool (derived view, therefore ops).
6///
7
8#[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/// Compute pool-level metrics from the registry.
17#[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///
47/// TESTS
48///
49
50#[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}