1use super::io;
4use super::planner::ResidentWorkItem;
5use super::protocol;
6use super::protocol_api::{validate_control_bytes, validate_debug_log_bytes};
7use super::readback::ResidentQueueReadback;
8use super::scheduler::write_default_priority_offsets;
9use super::ResidentWorkQueue;
10use crate::PipelineError;
11
12#[derive(Debug)]
15pub struct ResidentQueueBuffers {
16 control_bytes: Vec<u8>,
17 ring_bytes: Vec<u8>,
18 debug_log_bytes: Vec<u8>,
19 io_queue_bytes: Vec<u8>,
20 slot_count: u32,
21}
22
23impl Clone for ResidentQueueBuffers {
24 fn clone(&self) -> Self {
25 Self {
26 control_bytes: self.control_bytes.clone(),
27 ring_bytes: self.ring_bytes.clone(),
28 debug_log_bytes: self.debug_log_bytes.clone(),
29 io_queue_bytes: self.io_queue_bytes.clone(),
30 slot_count: self.slot_count,
31 }
32 }
33}
34
35impl PartialEq for ResidentQueueBuffers {
36 fn eq(&self, other: &Self) -> bool {
37 self.control_bytes == other.control_bytes
38 && self.ring_bytes == other.ring_bytes
39 && self.debug_log_bytes == other.debug_log_bytes
40 && self.io_queue_bytes == other.io_queue_bytes
41 && self.slot_count == other.slot_count
42 }
43}
44
45impl Eq for ResidentQueueBuffers {}
46
47impl ResidentQueueBuffers {
48 pub fn new(
54 slot_count: u32,
55 tenant_count: u32,
56 observable_slots: u32,
57 ) -> Result<Self, PipelineError> {
58 let control_capacity = protocol::control_byte_len(observable_slots).ok_or_else(|| {
59 PipelineError::Backend(
60 "megakernel resident control byte length overflowed usize. Fix: shard observable resident buffers before allocation."
61 .to_string(),
62 )
63 })?;
64 let ring_capacity = protocol::ring_byte_len(slot_count).ok_or_else(|| {
65 PipelineError::Backend(
66 "megakernel resident ring byte length overflowed usize. Fix: shard resident rings before allocation."
67 .to_string(),
68 )
69 })?;
70 let debug_log_capacity =
71 protocol::debug_log_byte_len(protocol::debug::RECORD_CAPACITY).ok_or_else(|| {
72 PipelineError::Backend(
73 "megakernel resident debug-log byte length overflowed usize. Fix: reduce debug record capacity before allocation."
74 .to_string(),
75 )
76 })?;
77 let io_queue_capacity = io::empty_io_queue_byte_len(io::IO_SLOT_COUNT)?;
78 let mut control_bytes = Vec::new();
79 reserve_resident_bytes(
80 &mut control_bytes,
81 control_capacity,
82 "control",
83 "shard observable resident buffers before allocation",
84 )?;
85 let mut ring_bytes = Vec::new();
86 reserve_resident_bytes(
87 &mut ring_bytes,
88 ring_capacity,
89 "ring",
90 "shard resident rings before allocation",
91 )?;
92 let mut debug_log_bytes = Vec::new();
93 reserve_resident_bytes(
94 &mut debug_log_bytes,
95 debug_log_capacity,
96 "debug-log",
97 "reduce debug record capacity before allocation",
98 )?;
99 let mut io_queue_bytes = Vec::new();
100 reserve_resident_bytes(
101 &mut io_queue_bytes,
102 io_queue_capacity,
103 "io-queue",
104 "reduce resident IO queue capacity before allocation",
105 )?;
106 let mut buffers = Self {
107 control_bytes,
108 ring_bytes,
109 debug_log_bytes,
110 io_queue_bytes,
111 slot_count,
112 };
113 buffers.reset(tenant_count, observable_slots)?;
114 Ok(buffers)
115 }
116
117 pub fn reset(&mut self, tenant_count: u32, observable_slots: u32) -> Result<(), PipelineError> {
123 ResidentWorkQueue::try_encode_control_into(
124 false,
125 tenant_count,
126 observable_slots,
127 &mut self.control_bytes,
128 )?;
129 write_default_priority_offsets(&mut self.control_bytes, self.slot_count)?;
130 ResidentWorkQueue::try_encode_empty_ring_into(self.slot_count, &mut self.ring_bytes)?;
131 ResidentWorkQueue::try_encode_empty_debug_log_into(
132 protocol::debug::RECORD_CAPACITY,
133 &mut self.debug_log_bytes,
134 )?;
135 io::try_encode_empty_io_queue_into(io::IO_SLOT_COUNT, &mut self.io_queue_bytes)?;
136 Ok(())
137 }
138
139 pub fn from_parts(
145 slot_count: u32,
146 control_bytes: Vec<u8>,
147 ring_bytes: Vec<u8>,
148 debug_log_bytes: Vec<u8>,
149 io_queue_bytes: Vec<u8>,
150 ) -> Result<Self, PipelineError> {
151 validate_control_bytes(&control_bytes)?;
152 validate_debug_log_bytes(&debug_log_bytes)?;
153 io::validate_io_queue_bytes(&io_queue_bytes)?;
154 let expected_ring_bytes = protocol::ring_byte_len(slot_count).ok_or_else(|| {
155 PipelineError::Backend(
156 "megakernel resident ring byte length overflowed usize. Fix: shard resident rings before allocation."
157 .to_string(),
158 )
159 })?;
160 if ring_bytes.len() != expected_ring_bytes {
161 return Err(PipelineError::Backend(format!(
162 "megakernel resident ring has {} bytes, expected {expected_ring_bytes}. Fix: build resident rings with the same slot_count as the Megakernel handle.",
163 ring_bytes.len()
164 )));
165 }
166 Ok(Self {
167 control_bytes,
168 ring_bytes,
169 debug_log_bytes,
170 io_queue_bytes,
171 slot_count,
172 })
173 }
174
175 pub fn publish_slot(
182 &mut self,
183 slot_idx: u32,
184 tenant_id: u32,
185 opcode: u32,
186 args: &[u32],
187 ) -> Result<(), PipelineError> {
188 ResidentWorkQueue::publish_slot(&mut self.ring_bytes, slot_idx, tenant_id, opcode, args)
189 }
190
191 pub fn publish_work_items(
199 &mut self,
200 start_slot: u32,
201 tenant_id: u32,
202 items: &[ResidentWorkItem],
203 ) -> Result<u32, PipelineError> {
204 ResidentWorkQueue::publish_work_items(&mut self.ring_bytes, start_slot, tenant_id, items)
205 }
206
207 pub fn apply_readback(&mut self, readback: ResidentQueueReadback) {
209 self.control_bytes = readback.control_bytes;
210 self.ring_bytes = readback.ring_bytes;
211 self.debug_log_bytes = readback.debug_log_bytes;
212 self.io_queue_bytes = readback.io_queue_bytes;
213 }
214
215 #[must_use]
217 pub fn snapshot_readback(&self) -> ResidentQueueReadback {
218 ResidentQueueReadback {
219 control_bytes: self.control_bytes.clone(),
220 ring_bytes: self.ring_bytes.clone(),
221 debug_log_bytes: self.debug_log_bytes.clone(),
222 io_queue_bytes: self.io_queue_bytes.clone(),
223 }
224 }
225
226 pub fn snapshot_readback_into(&self, out: &mut ResidentQueueReadback) {
228 out.control_bytes.clone_from(&self.control_bytes);
229 out.ring_bytes.clone_from(&self.ring_bytes);
230 out.debug_log_bytes.clone_from(&self.debug_log_bytes);
231 out.io_queue_bytes.clone_from(&self.io_queue_bytes);
232 }
233
234 #[must_use]
236 pub fn control_bytes(&self) -> &[u8] {
237 &self.control_bytes
238 }
239
240 #[must_use]
242 pub fn ring_bytes(&self) -> &[u8] {
243 &self.ring_bytes
244 }
245
246 #[must_use]
248 pub fn ring_bytes_mut(&mut self) -> &mut [u8] {
249 &mut self.ring_bytes
250 }
251
252 #[must_use]
254 pub fn debug_log_bytes(&self) -> &[u8] {
255 &self.debug_log_bytes
256 }
257
258 #[must_use]
260 pub fn io_queue_bytes(&self) -> &[u8] {
261 &self.io_queue_bytes
262 }
263
264 #[must_use]
266 pub const fn slot_count(&self) -> u32 {
267 self.slot_count
268 }
269}
270
271fn reserve_resident_bytes(
272 bytes: &mut Vec<u8>,
273 capacity: usize,
274 label: &'static str,
275 fix: &'static str,
276) -> Result<(), PipelineError> {
277 vyre_foundation::allocation::try_reserve_vec_to_capacity(bytes, capacity).map_err(|error| {
278 PipelineError::Backend(format!(
279 "megakernel resident {label} byte reservation failed for {capacity} bytes: {error}. Fix: {fix}."
280 ))
281 })
282}