maple_runtime/allocator/
mod.rs1use crate::types::AttentionConfig;
6use crate::types::*;
7use dashmap::DashMap;
8
9pub struct AttentionAllocator {
13 budgets: DashMap<ResonatorId, AttentionBudget>,
15
16 #[allow(dead_code)]
18 config: AttentionConfig,
19}
20
21impl AttentionAllocator {
22 pub fn new(config: &AttentionConfig) -> Self {
23 Self {
24 budgets: DashMap::new(),
25 config: config.clone(),
26 }
27 }
28
29 pub async fn allocate_budget(
31 &self,
32 resonator: &ResonatorId,
33 spec: &AttentionBudgetSpec,
34 ) -> Result<(), String> {
35 let mut budget = AttentionBudget::new(spec.total_capacity);
36
37 if let Some(reserve) = spec.safety_reserve {
38 budget.safety_reserve = reserve;
39 }
40
41 if let Some(threshold) = spec.exhaustion_threshold {
42 budget.exhaustion_threshold = threshold;
43 }
44
45 self.budgets.insert(*resonator, budget);
46
47 tracing::debug!(
48 "Allocated attention budget for {}: {} total",
49 resonator,
50 spec.total_capacity
51 );
52
53 Ok(())
54 }
55
56 pub async fn allocate(
60 &self,
61 resonator: &ResonatorId,
62 amount: u64,
63 ) -> Result<AllocationToken, AttentionError> {
64 let budget = self
65 .budgets
66 .get_mut(resonator)
67 .ok_or(AttentionError::ResonatorNotFound)?;
68
69 let available = budget.available();
70
71 if amount > available {
72 return Err(AttentionError::InsufficientAttention {
73 requested: amount,
74 available,
75 });
76 }
77
78 let token = AllocationToken::new(*resonator, amount);
79
80 tracing::trace!(
83 "Allocated {} attention for {} (available: {})",
84 amount,
85 resonator,
86 available - amount
87 );
88
89 Ok(token)
90 }
91
92 pub async fn allocate_more(
94 &self,
95 resonator: &ResonatorId,
96 amount: u64,
97 ) -> Result<(), AttentionError> {
98 let budget = self
99 .budgets
100 .get_mut(resonator)
101 .ok_or(AttentionError::ResonatorNotFound)?;
102
103 let available = budget.available();
104
105 if amount > available {
106 return Err(AttentionError::InsufficientAttention {
107 requested: amount,
108 available,
109 });
110 }
111
112 Ok(())
115 }
116
117 pub async fn release_partial(&self, resonator: &ResonatorId, amount: u64) {
119 if let Some(_budget) = self.budgets.get_mut(resonator) {
120 tracing::trace!("Released {} attention for {}", amount, resonator);
122 }
123 }
124
125 pub async fn release_all(&self, resonator: &ResonatorId, amount: u64) {
127 if let Some(_budget) = self.budgets.get_mut(resonator) {
128 tracing::trace!("Released all {} attention for {}", amount, resonator);
130 }
131 }
132
133 pub fn is_exhaustion_imminent(&self, resonator: &ResonatorId) -> bool {
135 if let Some(budget) = self.budgets.get(resonator) {
136 return budget.is_exhaustion_imminent();
137 }
138 false
139 }
140
141 pub async fn available_for_coupling(
143 &self,
144 resonator: &ResonatorId,
145 ) -> Result<u64, AttentionError> {
146 let budget = self
147 .budgets
148 .get(resonator)
149 .ok_or(AttentionError::ResonatorNotFound)?;
150
151 Ok(budget.available())
152 }
153
154 pub async fn get_budget(&self, resonator: &ResonatorId) -> Option<AttentionBudget> {
156 self.budgets.get(resonator).map(|r| r.clone())
157 }
158
159 pub async fn restore_budget(
161 &self,
162 resonator: &ResonatorId,
163 budget: &AttentionBudget,
164 ) -> Result<(), String> {
165 self.budgets.insert(*resonator, budget.clone());
166 tracing::debug!("Restored attention budget for {}", resonator);
167 Ok(())
168 }
169
170 pub async fn rebalance(&self, _resonator: &ResonatorId) {
174 tracing::debug!("Rebalancing attention (placeholder)");
179 }
180
181 pub fn remove_budget(&self, resonator: &ResonatorId) {
183 self.budgets.remove(resonator);
184 }
185}