1#![forbid(non_ascii_idents)]
158#![deny(
159 macro_use_extern_crate,
160 missing_copy_implementations,
161 missing_debug_implementations,
162 rust_2018_idioms,
163 rust_2021_compatibility,
164 trivial_casts,
165 trivial_numeric_casts,
166 unused_extern_crates,
167 unused_import_braces,
168 unused_qualifications
169)]
170#![warn(
171 clippy::nursery,
172 clippy::pedantic,
173 clippy::mutex_atomic,
174 clippy::rc_buffer,
175 clippy::rc_mutex
176)]
177#![allow(
178 clippy::cast_possible_truncation,
179 clippy::cast_possible_wrap,
180 clippy::cast_precision_loss,
181 clippy::cast_sign_loss,
182 clippy::missing_errors_doc,
183 clippy::missing_panics_doc,
184 clippy::must_use_candidate,
185 clippy::too_many_arguments,
186 clippy::too_many_lines
187)]
188
189mod cache;
190mod element;
191mod error;
192mod factory;
193mod format;
194mod header;
195mod qio;
196
197use std::cell::Cell;
198use std::fs::File;
199use std::io;
200use std::marker::PhantomData;
201use std::path::Path;
202
203use cache::OffsetCache;
204pub use cache::OffsetCacheKind;
205pub(crate) use element::Element;
206pub use error::Error;
207pub(crate) use error::{Result, maybe_inject_failpoint};
208pub(crate) use format::{
209 ExpansionPlan, FormatState, LegacyHeaderState, QueueMetadata, V2Format, V2OpenState,
210};
211pub(crate) use header::{SlotData, V2_INITIAL_LEN};
212pub(crate) use qio::{DataRing, DataRingMut, DeferredSyncPhase, QueueFileInner};
213
214#[derive(Debug)]
215pub struct QueueFile {
216 pub(crate) inner: QueueFileInner,
217 format: FormatState,
218 elem_cnt: usize,
219 first: Element,
220 last: Element,
221 pub(crate) capacity: u64,
222 overwrite_on_remove: bool,
223 skip_write_header_on_add: bool,
224 cache: OffsetCache,
225 write_buf: Vec<u8>,
227 #[allow(dead_code)]
228 _marker: PhantomData<Cell<()>>,
229}
230
231impl Drop for QueueFile {
232 fn drop(&mut self) {
233 if self.skip_write_header_on_add && self.inner.file.is_some() {
234 let _ = self.sync_header();
235 }
236 }
237}
238
239impl QueueFile {
240 pub(crate) const INITIAL_LENGTH: u64 = 4096;
241 const WRITE_BUF_FLUSH_LEN: usize = QueueFileInner::TRANSFER_BUFFER_SIZE;
243
244 #[inline]
245 const fn data_start(&self) -> u64 {
246 self.format.data_start()
247 }
248
249 fn to_logical(&self, phys: u64, what: &str) -> Result<u64> {
251 let data_start = self.data_start();
252 phys.checked_sub(data_start).ok_or_else(|| Error::OutOfBounds {
253 msg: format!("{what} {phys} < data_start {data_start}"),
254 })
255 }
256
257 pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: u64) -> Result<Self> {
261 factory::open_internal_full(path, true, false, capacity, true)
262 }
263
264 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
266 Self::with_capacity(path, Self::INITIAL_LENGTH)
267 }
268
269 pub fn open_legacy<P: AsRef<Path>>(path: P) -> Result<Self> {
271 factory::open_internal_full(path, true, true, Self::INITIAL_LENGTH, false)
272 }
273
274 pub(crate) fn build_legacy_queue_file(
275 file: File, state: LegacyHeaderState, capacity: u64, overwrite_on_remove: bool,
276 ) -> Result<Self> {
277 let mut queue_file = Self {
278 inner: QueueFileInner {
279 file: Some(file),
280 file_len: state.file_len,
281 expected_seek: 0,
282 last_seek: Some(32),
283 transfer_buf: vec![0u8; QueueFileInner::TRANSFER_BUFFER_SIZE].into_boxed_slice(),
284 sync_writes: cfg!(not(test)),
285 deferred_sync_phase: None,
286 },
287 format: state.format,
288 elem_cnt: state.elem_cnt,
289 first: Element::EMPTY,
290 last: Element::EMPTY,
291 capacity,
292 overwrite_on_remove,
293 skip_write_header_on_add: false,
294 cache: OffsetCache::new(),
295 write_buf: Vec::new(),
296 _marker: PhantomData,
297 };
298
299 if state.file_len < capacity {
300 queue_file.inner.sync_set_len(queue_file.capacity)?;
301 }
302
303 if state.elem_cnt > 0 {
304 let first_logical = queue_file.to_logical(state.first_pos, "first_pos")?;
305 let last_logical = queue_file.to_logical(state.last_pos, "last_pos")?;
306
307 queue_file.first = queue_file.read_element_at(first_logical)?;
308 queue_file.last = queue_file.read_element_at(last_logical)?;
309 }
310
311 Ok(queue_file)
312 }
313
314 pub(crate) fn build_v2_queue_file(
315 mut inner: QueueFileInner, open_state: V2OpenState, capacity: u64,
316 overwrite_on_remove: bool,
317 ) -> Self {
318 inner.file_len = open_state.slot.file_length;
319
320 Self {
321 inner,
322 format: FormatState::V2(V2Format {
323 active_slot: open_state.active_slot,
324 generation: open_state.slot.generation,
325 next_seq: open_state.slot.next_sequence_number,
326 }),
327 elem_cnt: open_state.elem_cnt,
328 first: Element::EMPTY,
329 last: Element::EMPTY,
330 capacity: capacity.max(V2_INITIAL_LEN),
331 overwrite_on_remove,
332 skip_write_header_on_add: false,
333 cache: OffsetCache::new(),
334 write_buf: Vec::new(),
335 _marker: PhantomData,
336 }
337 }
338
339 pub(crate) fn initialize_v2_endpoints(&mut self, slot: SlotData) -> Result<()> {
340 if self.elem_cnt == 0 {
341 return Ok(());
342 }
343
344 let first_logical = self.to_logical(slot.first_position, "v2 first_pos")?;
345 let last_logical = self.to_logical(slot.last_position, "v2 last_pos")?;
346
347 let last_header = self.format.validate_v2_element_header(&self.ring(), last_logical)?;
348 ensure!(last_header.seq == slot.next_sequence_number - 1, SequenceMismatch {
349 expected: slot.next_sequence_number - 1,
350 found: last_header.seq
351 });
352
353 self.last =
354 Element { pos: last_logical, len: last_header.payload_len, seq: last_header.seq };
355
356 self.first = match self.format.validate_v2_element_header(&self.ring(), first_logical) {
357 Ok(first_header) => {
358 Element { pos: first_logical, len: first_header.payload_len, seq: first_header.seq }
359 }
360 Err(_) => self.recover_v2_head(last_logical, last_header.seq, self.elem_cnt)?,
361 };
362
363 Ok(())
364 }
365
366 fn recover_v2_head(
368 &self, last_logical_pos: u64, last_seq: u64, elem_cnt: usize,
369 ) -> Result<Element> {
370 let mut pos = last_logical_pos;
371
372 for step in 0..elem_cnt {
373 let expected_seq =
374 last_seq.checked_sub(step as u64).ok_or_else(|| Error::InvalidValue {
375 msg: format!(
376 "v2 recovery: tail seq {last_seq} too small for element_count {elem_cnt}"
377 ),
378 })?;
379
380 let header = self.format.validate_v2_element_header(&self.ring(), pos)?;
381 ensure!(header.seq == expected_seq, SequenceMismatch {
382 expected: expected_seq,
383 found: header.seq
384 });
385
386 if step + 1 == elem_cnt {
387 return Ok(Element { pos, len: header.payload_len, seq: header.seq });
388 }
389
390 ensure!(header.prev_pos != 0, InvalidValue {
391 msg: format!("v2 recovery: walked {} elements but expected {}", step + 1, elem_cnt)
392 });
393 pos = self.to_logical(header.prev_pos, "v2 recovery: prev_pos")?;
394 }
395
396 Err(Error::CorruptedFile {
397 msg: "v2 recovery: could not walk expected live element count".to_string(),
398 })
399 }
400
401 #[inline]
404 pub const fn overwrite_on_remove(&self) -> bool {
405 self.overwrite_on_remove
406 }
407
408 #[deprecated(since = "1.4.7", note = "Use `overwrite_on_remove` instead.")]
409 pub const fn get_overwrite_on_remove(&self) -> bool {
410 self.overwrite_on_remove()
411 }
412
413 #[inline]
414 pub fn set_overwrite_on_remove(&mut self, value: bool) {
415 self.overwrite_on_remove = value;
416 }
417
418 #[inline]
419 pub const fn sync_writes(&self) -> bool {
420 self.inner.sync_writes
421 }
422
423 #[deprecated(since = "1.4.7", note = "Use `sync_writes` instead.")]
424 pub const fn get_sync_writes(&self) -> bool {
425 self.sync_writes()
426 }
427
428 #[inline]
429 pub fn set_sync_writes(&mut self, value: bool) {
430 self.inner.sync_writes = value;
431 }
432
433 #[inline]
434 pub const fn skip_write_header_on_add(&self) -> bool {
435 self.skip_write_header_on_add
436 }
437
438 #[deprecated(since = "1.4.7", note = "Use `skip_write_header_on_add` instead.")]
439 pub const fn get_skip_write_header_on_add(&self) -> bool {
440 self.skip_write_header_on_add()
441 }
442
443 #[inline]
444 pub fn set_skip_write_header_on_add(&mut self, value: bool) {
445 self.skip_write_header_on_add = value;
446 }
447
448 #[inline]
449 pub const fn cache_offset_policy(&self) -> Option<OffsetCacheKind> {
450 self.cache.kind
451 }
452
453 #[deprecated(since = "1.4.7", note = "Use `cache_offset_policy` instead.")]
454 pub const fn get_cache_offset_policy(&self) -> Option<OffsetCacheKind> {
455 self.cache_offset_policy()
456 }
457
458 #[inline]
459 pub fn set_cache_offset_policy(&mut self, kind: impl Into<Option<OffsetCacheKind>>) {
460 self.cache.set_policy(kind);
461 }
462
463 #[inline]
464 pub const fn is_empty(&self) -> bool {
465 self.elem_cnt == 0
466 }
467
468 #[inline]
469 pub const fn size(&self) -> usize {
470 self.elem_cnt
471 }
472
473 pub fn sync_all(&mut self) -> Result<()> {
474 if self.skip_write_header_on_add {
475 self.inner.file_mut()?.sync_data()?;
476 self.sync_header()?;
477 }
478
479 Ok(self.inner.file_mut()?.sync_all()?)
480 }
481
482 pub fn add_n(&mut self, elems: impl IntoIterator<Item = impl AsRef<[u8]>>) -> Result<()> {
485 let elems: Vec<_> = elems.into_iter().collect();
486 if elems.is_empty() {
487 return Ok(());
488 }
489
490 let mut total_span: u64 = 0;
491 for elem in &elems {
492 let len = elem.as_ref().len();
493 ensure!(i32::try_from(len).is_ok(), Error::ElementTooBig);
494 total_span = total_span.saturating_add(self.format.elem_span(len));
495 }
496 ensure!(self.elem_cnt + elems.len() < i32::MAX as usize, Error::TooManyElements);
497
498 self.expand_if_necessary(total_span)?;
499
500 let format = self.format;
501 let base_seq = format.next_seq();
502 let elem_cnt = self.elem_cnt;
503 let prev_last = if self.is_empty() { None } else { Some(self.last) };
504 let start_pos =
505 prev_last.map_or(0, |last| self.ring().add(last.pos, self.elem_span(last.len)));
506
507 let cache = &self.cache;
511 let mut buf = std::mem::take(&mut self.write_buf);
512 let result = self.inner.with_deferred_sync(DeferredSyncPhase::AppendBatch, |inner| {
513 let mut ring = DataRingMut::new(inner, format.data_start());
514 let mut prev = prev_last;
515 let mut pos = start_pos;
516 let mut flush_pos = start_pos;
517
518 for (i, elem) in elems.iter().enumerate() {
519 let payload = elem.as_ref();
520 let seq = if base_seq == 0 { 0 } else { base_seq + i as u64 };
521 format.encode_element(&mut buf, payload, seq, prev.map(|e| e.pos));
522
523 let entry = Element { pos, len: payload.len(), seq };
524 cache.cache_elem_if_needed(elem_cnt + i, entry, elem_cnt + i + 1, 1);
525 prev = Some(entry);
526 pos = ring.add(pos, format.elem_span(payload.len()));
527
528 if buf.len() >= Self::WRITE_BUF_FLUSH_LEN {
529 ring.write_at(flush_pos, &buf)?;
530 buf.clear();
531 flush_pos = pos;
532 }
533 }
534
535 if !buf.is_empty() {
536 ring.write_at(flush_pos, &buf)?;
537 }
538
539 Ok(prev)
540 });
541
542 buf.clear();
543 buf.shrink_to(Self::WRITE_BUF_FLUSH_LEN);
544 self.write_buf = buf;
545
546 let last = match result {
547 Ok(last) => last.expect("at least one element was appended"),
548 Err(err) => {
549 self.cache.clear();
551 return Err(err);
552 }
553 };
554
555 if elem_cnt == 0 {
556 self.first = Element { pos: start_pos, len: elems[0].as_ref().len(), seq: base_seq };
557 }
558 self.last = last;
559 self.elem_cnt += elems.len();
560 if base_seq != 0 {
561 self.format.set_next_seq(base_seq + elems.len() as u64);
562 }
563
564 if !self.skip_write_header_on_add {
565 self.sync_header()?;
566 }
567
568 Ok(())
569 }
570
571 #[inline]
572 pub fn add(&mut self, buf: &[u8]) -> Result<()> {
573 self.add_n(std::iter::once(buf))
574 }
575
576 pub fn peek(&self) -> Result<Option<Vec<u8>>> {
579 if self.is_empty() {
580 return Ok(None);
581 }
582
583 let mut buf = vec![0; self.first.len];
584 self.read_payload(&self.first, &mut buf)?;
585 Ok(Some(buf))
586 }
587
588 pub fn peek_into(&self, buf: &mut Vec<u8>) -> Result<bool> {
589 if self.is_empty() {
590 return Ok(false);
591 }
592
593 buf.resize(self.first.len, 0);
594 self.read_payload(&self.first, buf)?;
595 Ok(true)
596 }
597
598 fn read_payload(&self, elem: &Element, buf: &mut [u8]) -> Result<()> {
600 let ring = self.ring();
601 let payload_start = ring.add(elem.pos, self.elem_hdr_len());
602 ring.read_at(payload_start, buf)?;
603 self.format.validate_footer(&ring, payload_start, elem, buf)
604 }
605
606 #[inline]
609 pub fn remove(&mut self) -> Result<()> {
610 self.remove_n(1)
611 }
612
613 pub fn remove_n(&mut self, n: usize) -> Result<()> {
614 if n == 0 || self.is_empty() {
615 return Ok(());
616 }
617
618 if n >= self.elem_cnt {
619 return self.clear();
620 }
621
622 #[cfg(debug_assertions)]
623 {
624 let offsets = self.cache.offsets.borrow();
625 debug_assert!(
626 offsets.iter().zip(offsets.iter().skip(1)).all(|(a, b)| a.0 < b.0),
627 "{:?}",
628 *offsets
629 );
630 }
631
632 let old_first_pos = self.first.pos;
633
634 let new_first = self.skip_elements_from(n)?;
635
636 let erase_total_len = if self.overwrite_on_remove {
637 self.ring().distance(old_first_pos, new_first.pos) as usize
638 } else {
639 0
640 };
641
642 self.elem_cnt -= n;
643 self.first = new_first;
644
645 self.sync_header()?;
646
647 self.cache.drop_up_to(n);
648
649 if self.overwrite_on_remove {
650 self.ring_mut().erase_at(old_first_pos, erase_total_len)?;
651 }
652
653 Ok(())
654 }
655
656 fn skip_elements_from(&self, n: usize) -> Result<Element> {
657 let (skipped, mut elem) = self.cache.cached_offset_up_to(n).unwrap_or((0, self.first));
658
659 let ring = self.ring();
660 for _ in skipped..n {
661 let next_pos = ring.add(elem.pos, self.elem_span(elem.len));
662 elem = self.format.read_element(&ring, next_pos)?;
663 }
664
665 Ok(elem)
666 }
667
668 pub fn clear(&mut self) -> Result<()> {
671 let new_cap = self.capacity.max(self.data_start());
672
673 self.elem_cnt = 0;
674 self.first = Element::EMPTY;
675 self.last = Element::EMPTY;
676
677 self.sync_header()?;
678
679 if self.overwrite_on_remove {
680 let ds = self.data_start();
681 let data_region_len = self.file_len().min(new_cap).saturating_sub(ds);
682 if data_region_len > 0 {
683 self.inner.with_deferred_sync(DeferredSyncPhase::ClearErase, |inner| {
684 inner.write_zero_chunks(ds, data_region_len as usize)
685 })?;
686 }
687 }
688
689 self.cache.clear();
690
691 if self.file_len() > new_cap {
692 self.inner.sync_set_len(new_cap)?;
693 }
694
695 Ok(())
696 }
697
698 #[inline]
701 pub const fn iter(&self) -> Iter<'_> {
702 Iter {
703 buffer: Vec::new(),
704 queue_file: self,
705 next_elem_index: 0,
706 next_elem_pos: self.first.pos,
707 }
708 }
709
710 #[inline]
713 const fn ring(&self) -> DataRing<'_> {
714 DataRing::new(&self.inner, self.format.data_start())
715 }
716
717 #[inline]
718 fn ring_mut(&mut self) -> DataRingMut<'_> {
719 let data_start = self.format.data_start();
720 DataRingMut::new(&mut self.inner, data_start)
721 }
722
723 #[inline]
724 fn read_element_at(&self, logical_pos: u64) -> Result<Element> {
725 self.format.read_element(&self.ring(), logical_pos)
726 }
727
728 #[inline]
729 pub const fn file_len(&self) -> u64 {
730 self.inner.file_len
731 }
732
733 #[inline]
734 pub const fn used_bytes(&self) -> u64 {
735 if self.elem_cnt == 0 {
736 self.data_start()
737 } else {
738 self.ring().distance(self.first.pos, self.last.pos)
739 + self.elem_span(self.last.len)
740 + self.data_start()
741 }
742 }
743
744 pub fn into_inner_file(mut self) -> Result<File> {
745 if self.skip_write_header_on_add {
746 self.sync_header()?;
747 }
748
749 self.inner.file.take().ok_or_else(|| Error::Io {
750 source: io::Error::new(io::ErrorKind::BrokenPipe, "file handle already consumed"),
751 })
752 }
753
754 #[inline]
757 const fn remaining_bytes(&self) -> u64 {
758 self.file_len() - self.used_bytes()
759 }
760
761 fn sync_header(&mut self) -> Result<()> {
762 let metadata = QueueMetadata {
763 file_len: self.file_len(),
764 elem_cnt: self.elem_cnt,
765 first_pos: self.first.pos,
766 last_pos: self.last.pos,
767 };
768 self.format.commit_header(&mut self.inner, metadata)
769 }
770
771 #[inline]
772 const fn elem_hdr_len(&self) -> u64 {
773 self.format.elem_hdr_len()
774 }
775
776 #[inline]
777 const fn elem_span(&self, payload_len: usize) -> u64 {
778 self.format.elem_span(payload_len)
779 }
780
781 fn compute_expanded_len(current_len: u64, mut remaining_bytes: u64, data_len: u64) -> u64 {
782 let mut prev_len = current_len;
783 let mut new_len = current_len;
784 while remaining_bytes < data_len {
785 remaining_bytes = remaining_bytes.saturating_add(prev_len);
786 new_len = prev_len.checked_shl(1).unwrap_or(u64::MAX);
787 prev_len = new_len;
788 }
789 new_len
790 }
791
792 fn compute_expansion_plan(&self, data_len: u64) -> Option<ExpansionPlan> {
793 let rem_bytes = self.remaining_bytes();
794 if rem_bytes >= data_len {
795 return None;
796 }
797
798 let orig_file_len = self.file_len();
799 let (end_of_last_elem, wraps) = self.calculate_tail_metrics();
800 let moved_count = if wraps { end_of_last_elem } else { 0 };
801
802 Some(ExpansionPlan {
803 orig_file_len,
804 new_len: Self::compute_expanded_len(orig_file_len, rem_bytes, data_len),
805 end_of_last_elem: self.data_start() + end_of_last_elem,
806 wraps,
807 moved_count,
808 })
809 }
810
811 const fn calculate_tail_metrics(&self) -> (u64, bool) {
812 if self.elem_cnt > 0 {
813 let ring = self.ring();
814 let end = ring.add(self.last.pos, self.format.elem_span(self.last.len));
815 (end, end <= self.first.pos)
816 } else {
817 (0, false)
818 }
819 }
820
821 fn relocate_wrapped_data(&mut self, plan: ExpansionPlan) -> Result<()> {
822 if !plan.wraps {
823 return Ok(());
824 }
825
826 self.ring_mut().relocate(plan.orig_file_len, plan.moved_count)?;
827
828 let first = self.first;
829 let last = self.last;
830 let elem_cnt = self.elem_cnt;
831 let format = self.format;
832
833 if let Some(new_last_pos) =
834 format.on_expansion(&mut self.ring_mut(), &plan, first, last, elem_cnt)?
835 {
836 self.last = Element { pos: new_last_pos, len: self.last.len, seq: self.last.seq };
837
838 maybe_inject_failpoint("v2_before_relocation_commit")?;
839
840 if self.overwrite_on_remove {
841 self.sync_header()?;
842 maybe_inject_failpoint("v2_after_relocation_commit_before_erase")?;
843 }
844 }
845
846 Ok(())
847 }
848
849 fn cleanup_after_expansion(&mut self, plan: ExpansionPlan) -> Result<()> {
850 if self.overwrite_on_remove {
851 self.ring_mut().erase_at(0, plan.moved_count as usize)?;
852 self.format.on_expansion_cleanup(&plan)?;
853 }
854
855 Ok(())
856 }
857
858 fn expand_if_necessary(&mut self, data_len: u64) -> Result<()> {
859 let Some(plan) = self.compute_expansion_plan(data_len) else {
860 return Ok(());
861 };
862
863 let bytes_used_before = self.used_bytes();
864 self.inner.sync_set_len(plan.new_len)?;
865 self.relocate_wrapped_data(plan)?;
866 self.cache.clear();
867 self.cleanup_after_expansion(plan)?;
868
869 let bytes_used_after = self.used_bytes();
870 debug_assert_eq!(bytes_used_before, bytes_used_after);
871
872 Ok(())
873 }
874}
875
876impl<'a> IntoIterator for &'a QueueFile {
877 type IntoIter = Iter<'a>;
878 type Item = Vec<u8>;
879
880 fn into_iter(self) -> Self::IntoIter {
881 self.iter()
882 }
883}
884
885#[derive(Debug)]
887pub struct Iter<'a> {
888 queue_file: &'a QueueFile,
889 buffer: Vec<u8>,
890 next_elem_index: usize,
891 next_elem_pos: u64,
892}
893
894impl Iterator for Iter<'_> {
895 type Item = Vec<u8>;
896
897 fn next(&mut self) -> Option<Self::Item> {
898 let current = self.current_element()?;
899 let mut buf = vec![0; current.len];
900 self.queue_file.read_payload(¤t, &mut buf).ok()?;
901 self.advance(current);
902 Some(buf)
903 }
904
905 fn size_hint(&self) -> (usize, Option<usize>) {
906 let elems_left = self.queue_file.elem_cnt - self.next_elem_index;
907 (elems_left, Some(elems_left))
908 }
909
910 fn nth(&mut self, n: usize) -> Option<Self::Item> {
911 let target_idx = self.next_elem_index.checked_add(n)?;
912
913 if target_idx >= self.queue_file.elem_cnt {
914 self.next_elem_index = self.queue_file.elem_cnt;
915 return None;
916 }
917
918 self.jump_to_cache_if_closer(target_idx);
919
920 while self.next_elem_index < target_idx {
921 let current = self.current_element()?;
922 self.advance(current);
923 }
924
925 self.next()
926 }
927}
928
929impl Iter<'_> {
930 fn jump_to_cache_if_closer(&mut self, target_idx: usize) {
931 if let Some((index, elem)) = self.queue_file.cache.cached_offset_up_to(target_idx) {
932 if index > self.next_elem_index {
933 self.next_elem_index = index;
934 self.next_elem_pos = elem.pos;
935 }
936 }
937 }
938
939 fn current_element(&self) -> Option<Element> {
941 if self.next_elem_index >= self.queue_file.elem_cnt {
942 return None;
943 }
944
945 let current = self.queue_file.read_element_at(self.next_elem_pos).ok()?;
946 (current.len as u64 <= self.queue_file.ring().capacity()).then_some(current)
947 }
948
949 fn advance(&mut self, current: Element) {
951 let queue_file = self.queue_file;
952 queue_file.cache.cache_elem_if_needed(
953 self.next_elem_index,
954 current,
955 queue_file.elem_cnt,
956 1,
957 );
958 self.next_elem_pos = queue_file.ring().add(current.pos, queue_file.elem_span(current.len));
959 self.next_elem_index += 1;
960 }
961
962 pub fn borrowed_next(&mut self) -> Option<&[u8]> {
963 let current = self.current_element()?;
964
965 if current.len > self.buffer.len() {
966 self.buffer.resize(current.len, 0);
967 }
968 self.queue_file.read_payload(¤t, &mut self.buffer[..current.len]).ok()?;
969 self.advance(current);
970
971 Some(&self.buffer[..current.len])
972 }
973}
974
975#[cfg(test)]
976mod tests {
977 use std::fs::OpenOptions;
978
979 use super::*;
980
981 fn create_inner(len: u64) -> (QueueFileInner, auto_delete_path::AutoDeletePath) {
982 let p = auto_delete_path::AutoDeletePath::temp();
983 let file =
984 OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&p).unwrap();
985 file.set_len(len).unwrap();
986 (
987 QueueFileInner {
988 file: Some(file),
989 file_len: len,
990 expected_seek: 0,
991 last_seek: None,
992 transfer_buf: vec![0u8; 1024].into_boxed_slice(),
993 sync_writes: false,
994 deferred_sync_phase: None,
995 },
996 p,
997 )
998 }
999
1000 #[test]
1001 fn test_data_ring_addressing() {
1002 let (inner, _p) = create_inner(100);
1003 let ring = DataRing::new(&inner, 20);
1004
1005 assert_eq!(ring.capacity(), 80);
1006 assert_eq!(ring.phys_pos(0), 20);
1007 assert_eq!(ring.phys_pos(79), 99);
1008 assert_eq!(ring.phys_pos(80), 20);
1009 assert_eq!(ring.phys_pos(160), 20);
1010
1011 assert_eq!(ring.add(10, 20), 30);
1012 assert_eq!(ring.add(70, 20), 10);
1013
1014 assert_eq!(ring.distance(10, 30), 20);
1015 assert_eq!(ring.distance(70, 10), 20);
1016 }
1017
1018 #[test]
1019 fn test_data_ring_io() {
1020 let (mut inner, _p) = create_inner(100);
1021 let mut ring_mut = DataRingMut::new(&mut inner, 20);
1022
1023 let data = b"hello world";
1024 ring_mut.write_at(10, data).unwrap();
1025 let mut buf = [0u8; 11];
1026 ring_mut.as_read_only().read_at(10, &mut buf).unwrap();
1027 assert_eq!(&buf, data);
1028
1029 let data2 = b"wrapmebase";
1030 ring_mut.write_at(75, data2).unwrap();
1031 let mut buf2 = [0u8; 10];
1032 ring_mut.as_read_only().read_at(75, &mut buf2).unwrap();
1033 assert_eq!(&buf2, data2);
1034
1035 let mut phys_buf = [0u8; 5];
1036 ring_mut.inner.read_exact_at(95, &mut phys_buf).unwrap();
1037 assert_eq!(&phys_buf, b"wrapm");
1038 ring_mut.inner.read_exact_at(20, &mut phys_buf).unwrap();
1039 assert_eq!(&phys_buf, b"ebase");
1040 }
1041
1042 #[test]
1043 fn remove_n_reindexes_cached_offsets_without_dropping_survivors() {
1044 let path = auto_delete_path::AutoDeletePath::temp();
1045 let mut qf = QueueFile::with_capacity(&path, 4096).unwrap();
1046 qf.set_cache_offset_policy(Some(OffsetCacheKind::Linear { offset: 1 }));
1047
1048 for i in 0u8..8 {
1049 qf.add(&[i]).unwrap();
1050 }
1051
1052 assert_eq!(
1053 qf.cache.offsets.borrow().iter().map(|(idx, _)| *idx).collect::<Vec<_>>(),
1054 (1..8).collect::<Vec<_>>()
1055 );
1056
1057 qf.remove_n(3).unwrap();
1058
1059 assert_eq!(
1060 qf.cache.offsets.borrow().iter().map(|(idx, _)| *idx).collect::<Vec<_>>(),
1061 vec![3, 4, 5, 6, 7]
1062 );
1063 assert_eq!(qf.iter().map(|v| v[0]).collect::<Vec<_>>(), vec![3, 4, 5, 6, 7]);
1064 assert_eq!(qf.iter().nth(2).map(|v| v[0]), Some(5));
1065 }
1066
1067 #[test]
1068 fn cache_respects_max_size() {
1069 let path = auto_delete_path::AutoDeletePath::temp();
1070 let mut qf = QueueFile::with_capacity(&path, 1024 * 1024).unwrap();
1071 qf.set_cache_offset_policy(Some(OffsetCacheKind::Linear { offset: 1 }));
1072
1073 for i in 0u32..5000 {
1076 qf.add(&i.to_le_bytes()).unwrap();
1077 }
1078
1079 let cache_size = qf.cache.offsets.borrow().len();
1080 assert!(cache_size <= 4096);
1081 assert_eq!(cache_size, 4096);
1082
1083 assert_eq!(qf.cache.offsets.borrow().front().unwrap().0, 904);
1091 assert_eq!(qf.cache.offsets.borrow().back().unwrap().0, 4999);
1092 }
1093}