1use std::collections::VecDeque;
38use std::sync::{Arc, Condvar, Mutex};
39
40use rudb_common::{Error, Result};
41
42#[derive(Debug)]
47pub struct Request {
48 offset: u64,
49 buf: Vec<u8>,
50}
51
52impl Request {
53 #[must_use]
55 pub fn new(offset: u64, len: usize) -> Self {
56 Self { offset, buf: vec![0; len] }
57 }
58
59 #[must_use]
65 pub fn reusing(offset: u64, buf: Vec<u8>) -> Self {
66 Self { offset, buf }
67 }
68
69 #[must_use]
71 pub fn offset(&self) -> u64 {
72 self.offset
73 }
74
75 #[must_use]
77 pub fn len(&self) -> usize {
78 self.buf.len()
79 }
80
81 #[must_use]
83 pub fn is_empty(&self) -> bool {
84 self.buf.is_empty()
85 }
86
87 #[must_use]
89 pub fn end(&self) -> u64 {
90 self.offset + self.buf.len() as u64
91 }
92
93 #[must_use]
95 pub fn into_buffer(self) -> Vec<u8> {
96 self.buf
97 }
98}
99
100#[derive(Debug)]
106pub struct Response {
107 index: usize,
108 offset: u64,
109 read: usize,
110 buf: Vec<u8>,
111}
112
113impl Response {
114 #[must_use]
116 pub fn new(index: usize, offset: u64, read: usize, buf: Vec<u8>) -> Self {
117 Self { index, offset, read, buf }
118 }
119
120 #[must_use]
122 pub fn index(&self) -> usize {
123 self.index
124 }
125
126 #[must_use]
128 pub fn offset(&self) -> u64 {
129 self.offset
130 }
131
132 #[must_use]
134 pub fn read(&self) -> usize {
135 self.read
136 }
137
138 #[must_use]
140 pub fn bytes(&self) -> &[u8] {
141 &self.buf[..self.read]
142 }
143
144 #[must_use]
150 pub fn is_short(&self) -> bool {
151 self.read < self.buf.len()
152 }
153
154 #[must_use]
158 pub fn into_buffer(self) -> Vec<u8> {
159 self.buf
160 }
161}
162
163#[derive(Debug)]
164struct State {
165 slots: Vec<Option<Result<Response>>>,
167 ready: VecDeque<usize>,
169 outstanding: usize,
171 fillers: usize,
174}
175
176#[derive(Debug)]
177struct Shared {
178 state: Mutex<State>,
179 wake: Condvar,
180}
181
182impl Shared {
183 fn lock(&self) -> std::sync::MutexGuard<'_, State> {
184 self.state.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
187 }
188}
189
190#[derive(Debug)]
195pub struct Filler {
196 shared: Arc<Shared>,
197}
198
199impl Clone for Filler {
200 fn clone(&self) -> Self {
201 self.shared.lock().fillers += 1;
202 Self { shared: Arc::clone(&self.shared) }
203 }
204}
205
206impl Filler {
207 pub fn finish(&self, index: usize, outcome: Result<Response>) {
213 let mut state = self.shared.lock();
214 if state.slots.get(index).is_none_or(Option::is_some) {
215 return;
216 }
217 state.slots[index] = Some(outcome);
218 state.ready.push_back(index);
219 state.outstanding -= 1;
220 drop(state);
221 self.shared.wake.notify_all();
222 }
223}
224
225impl Drop for Filler {
226 fn drop(&mut self) {
227 let mut state = self.shared.lock();
228 state.fillers -= 1;
229 if state.fillers > 0 || state.outstanding == 0 {
230 return;
231 }
232 for index in 0..state.slots.len() {
237 if state.slots[index].is_some() {
238 continue;
239 }
240 state.slots[index] =
241 Some(Err(Error::io("the I/O backend stopped before this read finished")));
242 state.ready.push_back(index);
243 }
244 state.outstanding = 0;
245 drop(state);
246 self.shared.wake.notify_all();
247 }
248}
249
250#[derive(Debug)]
258pub struct Completion {
259 shared: Arc<Shared>,
260 taken: usize,
262}
263
264impl Completion {
265 #[must_use]
267 pub fn pending(count: usize) -> (Self, Filler) {
268 let mut slots = Vec::with_capacity(count);
269 slots.resize_with(count, || None);
270 let shared = Arc::new(Shared {
271 state: Mutex::new(State {
272 slots,
273 ready: VecDeque::with_capacity(count),
274 outstanding: count,
275 fillers: 1,
276 }),
277 wake: Condvar::new(),
278 });
279 (Self { shared: Arc::clone(&shared), taken: 0 }, Filler { shared })
280 }
281
282 #[must_use]
284 pub fn ready(responses: Vec<Result<Response>>) -> Self {
285 let (completion, filler) = Self::pending(responses.len());
286 for (index, outcome) in responses.into_iter().enumerate() {
287 filler.finish(index, outcome);
288 }
289 completion
290 }
291
292 #[must_use]
294 pub fn len(&self) -> usize {
295 self.shared.lock().slots.len()
296 }
297
298 #[must_use]
300 pub fn is_empty(&self) -> bool {
301 self.len() == 0
302 }
303
304 #[must_use]
309 pub fn ready_count(&self) -> usize {
310 self.shared.lock().ready.len()
311 }
312
313 #[must_use]
315 pub fn is_done(&self) -> bool {
316 self.shared.lock().outstanding == 0
317 }
318
319 pub fn take(&mut self) -> Option<Result<Response>> {
324 let mut state = self.shared.lock();
325 loop {
326 if let Some(index) = state.ready.pop_front() {
327 self.taken += 1;
328 return state.slots[index].take();
329 }
330 if state.outstanding == 0 {
331 return None;
332 }
333 state = self.shared.wake.wait(state).unwrap_or_else(std::sync::PoisonError::into_inner);
334 }
335 }
336
337 pub fn wait(mut self) -> Result<Vec<Response>> {
346 let mut state = self.shared.lock();
347 while state.outstanding > 0 {
348 state = self.shared.wake.wait(state).unwrap_or_else(std::sync::PoisonError::into_inner);
349 }
350 state.ready.clear();
351 self.taken = state.slots.len();
352 let mut out = Vec::with_capacity(state.slots.len());
353 let mut failure = None;
354 for slot in &mut state.slots {
355 match slot.take() {
356 Some(Ok(response)) => out.push(response),
357 Some(Err(error)) => failure = failure.or(Some(error)),
358 None => {}
359 }
360 }
361 match failure {
362 Some(error) => Err(error),
363 None => Ok(out),
364 }
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use std::sync::Arc;
371 use std::sync::atomic::{AtomicUsize, Ordering};
372
373 use rudb_common::Error;
374
375 use super::{Completion, Request, Response};
376
377 fn response(index: usize, bytes: &[u8]) -> Response {
378 Response::new(index, index as u64, bytes.len(), bytes.to_vec())
379 }
380
381 #[test]
382 fn a_request_states_its_length_through_its_buffer() {
383 let request = Request::new(64, 8);
384 assert_eq!(request.offset(), 64);
385 assert_eq!(request.len(), 8);
386 assert_eq!(request.end(), 72);
387 assert!(!request.is_empty());
388 assert_eq!(Request::reusing(0, vec![1, 2, 3]).len(), 3);
389 }
390
391 #[test]
392 fn wait_returns_responses_in_submission_order_however_they_finished() {
393 let (completion, filler) = Completion::pending(3);
394 filler.finish(2, Ok(response(2, b"cc")));
395 filler.finish(0, Ok(response(0, b"a")));
396 filler.finish(1, Ok(response(1, b"bbb")));
397 let responses = completion.wait().unwrap();
398 assert_eq!(responses.iter().map(Response::index).collect::<Vec<_>>(), [0, 1, 2]);
399 assert_eq!(responses[1].bytes(), b"bbb");
400 }
401
402 #[test]
403 fn take_returns_responses_in_completion_order_and_then_stops() {
404 let (mut completion, filler) = Completion::pending(2);
405 filler.finish(1, Ok(response(1, b"second")));
406 assert_eq!(completion.ready_count(), 1);
407 assert!(!completion.is_done());
408 assert_eq!(completion.take().unwrap().unwrap().index(), 1);
409 filler.finish(0, Ok(response(0, b"first")));
410 assert!(completion.is_done());
411 assert_eq!(completion.take().unwrap().unwrap().index(), 0);
412 assert!(completion.take().is_none());
413 }
414
415 #[test]
416 fn wait_reports_the_first_failure_by_position_not_by_arrival() {
417 let (completion, filler) = Completion::pending(3);
418 filler.finish(2, Err(Error::io("late")));
419 filler.finish(1, Err(Error::io("early")));
420 filler.finish(0, Ok(response(0, b"fine")));
421 let error = completion.wait().unwrap_err();
422 assert!(error.to_string().contains("early"), "{error}");
423 }
424
425 #[test]
426 fn a_short_read_is_a_response_and_not_an_error() {
427 let completion = Completion::ready(vec![Ok(Response::new(0, 0, 2, vec![7, 7, 0, 0]))]);
428 let responses = completion.wait().unwrap();
429 assert!(responses[0].is_short());
430 assert_eq!(responses[0].bytes(), &[7, 7]);
431 assert_eq!(responses[0].read(), 2);
432 }
433
434 #[test]
435 fn a_buffer_comes_back_out_of_the_response_to_be_used_again() {
436 let request = Request::reusing(0, vec![0; 4]);
437 let buf = request.into_buffer();
438 let response = Response::new(0, 0, 4, buf);
439 assert_eq!(response.into_buffer().len(), 4);
440 }
441
442 #[test]
443 fn a_backend_that_goes_away_wakes_the_waiter_instead_of_hanging_it() {
444 let (completion, filler) = Completion::pending(2);
446 filler.finish(0, Ok(response(0, b"one")));
447 drop(filler);
448 let error = completion.wait().unwrap_err();
449 assert!(error.to_string().contains("stopped before"), "{error}");
450 }
451
452 #[test]
453 fn the_last_filler_out_is_the_one_that_wakes_the_waiter() {
454 let (mut completion, filler) = Completion::pending(2);
455 let second = filler.clone();
456 drop(filler);
457 assert!(!completion.is_done());
458 second.finish(0, Ok(response(0, b"one")));
459 drop(second);
460 assert_eq!(completion.take().unwrap().unwrap().index(), 0);
461 assert!(completion.take().unwrap().is_err());
462 assert!(completion.take().is_none());
463 }
464
465 #[test]
466 fn filling_a_slot_twice_leaves_the_first_answer_in_place() {
467 let (mut completion, filler) = Completion::pending(1);
468 filler.finish(0, Ok(response(0, b"kept")));
469 filler.finish(0, Err(Error::io("ignored")));
470 assert_eq!(completion.take().unwrap().unwrap().bytes(), b"kept");
471 }
472
473 #[test]
474 fn a_waiter_blocks_until_another_thread_fills_the_last_slot() {
475 let (completion, filler) = Completion::pending(2);
476 let filled = Arc::new(AtomicUsize::new(0));
477 let counter = Arc::clone(&filled);
478 let worker = std::thread::spawn(move || {
479 for index in 0..2 {
480 std::thread::sleep(std::time::Duration::from_millis(5));
481 counter.fetch_add(1, Ordering::SeqCst);
482 filler.finish(index, Ok(response(index, b"x")));
483 }
484 });
485 assert_eq!(completion.wait().unwrap().len(), 2);
486 assert_eq!(filled.load(Ordering::SeqCst), 2);
487 worker.join().unwrap();
488 }
489}