arms/ports/latency.rs
1//! # Latency Port
2//!
3//! Trait for runtime latency measurement and adaptation.
4//!
5//! This enables the model to know its actual retrieval constraints:
6//! - How fast is the hot tier right now?
7//! - How much budget do I have for retrieval?
8//! - Should I use fewer, faster retrievals or more, slower ones?
9
10use std::time::Duration;
11
12/// Storage tier levels
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum Tier {
15 /// RAM storage - fastest
16 Hot,
17 /// NVMe storage - fast
18 Warm,
19 /// Archive storage - slow
20 Cold,
21}
22
23impl Tier {
24 /// Get expected latency range for this tier
25 pub fn expected_latency(&self) -> (Duration, Duration) {
26 match self {
27 Tier::Hot => (Duration::from_micros(1), Duration::from_millis(1)),
28 Tier::Warm => (Duration::from_millis(1), Duration::from_millis(10)),
29 Tier::Cold => (Duration::from_millis(10), Duration::from_millis(100)),
30 }
31 }
32}
33
34/// Latency measurement result
35#[derive(Debug, Clone)]
36pub struct LatencyMeasurement {
37 /// The tier that was measured
38 pub tier: Tier,
39
40 /// Measured latency for a single operation
41 pub latency: Duration,
42
43 /// Throughput (operations per second) if measured
44 pub throughput_ops: Option<f64>,
45
46 /// Timestamp of measurement
47 pub measured_at: std::time::Instant,
48}
49
50/// Budget allocation for retrieval operations
51#[derive(Debug, Clone)]
52pub struct LatencyBudget {
53 /// Total time budget for this retrieval batch
54 pub total: Duration,
55
56 /// Maximum time per individual retrieval
57 pub per_operation: Duration,
58
59 /// Maximum number of operations in this budget
60 pub max_operations: usize,
61}
62
63impl Default for LatencyBudget {
64 fn default() -> Self {
65 Self {
66 total: Duration::from_millis(50),
67 per_operation: Duration::from_millis(5),
68 max_operations: 10,
69 }
70 }
71}
72
73/// Tier statistics
74#[derive(Debug, Clone)]
75pub struct TierStats {
76 /// The tier
77 pub tier: Tier,
78
79 /// Number of points in this tier
80 pub count: usize,
81
82 /// Total size in bytes
83 pub size_bytes: usize,
84
85 /// Capacity in bytes
86 pub capacity_bytes: usize,
87
88 /// Usage ratio (0.0 to 1.0)
89 pub usage_ratio: f32,
90}
91
92/// Trait for latency measurement and adaptation
93///
94/// System adapters implement this trait.
95pub trait Latency: Send + Sync {
96 /// Probe a tier to measure current latency
97 ///
98 /// Performs a small test operation to measure actual latency.
99 fn probe(&mut self, tier: Tier) -> LatencyMeasurement;
100
101 /// Get the current latency budget
102 fn budget(&self) -> LatencyBudget;
103
104 /// Set a new latency budget
105 fn set_budget(&mut self, budget: LatencyBudget);
106
107 /// Get available capacity in a tier
108 fn available_capacity(&self, tier: Tier) -> usize;
109
110 /// Recommend which tier to use for an access pattern
111 ///
112 /// `expected_accesses` is the expected number of accesses for this data.
113 fn recommend_tier(&self, expected_accesses: u32) -> Tier;
114
115 /// Get statistics for a tier
116 fn tier_stats(&self, tier: Tier) -> TierStats;
117
118 /// Get statistics for all tiers
119 fn all_stats(&self) -> Vec<TierStats> {
120 vec![
121 self.tier_stats(Tier::Hot),
122 self.tier_stats(Tier::Warm),
123 self.tier_stats(Tier::Cold),
124 ]
125 }
126}