LCOV - code coverage report
Current view: top level - pageserver/src/tenant/ephemeral_file/zero_padded_read_write - zero_padded.rs (source / functions) Coverage Total Hit
Test: 691a4c28fe7169edd60b367c52d448a0a6605f1f.info Lines: 95.2 % 63 60
Test Date: 2024-05-10 13:18:37 Functions: 91.7 % 12 11

            Line data    Source code
       1              : //! A [`crate::virtual_file::owned_buffers_io::write::Buffer`] whose
       2              : //! unwritten range is guaranteed to be zero-initialized.
       3              : //! This is used by [`crate::tenant::ephemeral_file::zero_padded_read_write::RW::read_blk`]
       4              : //! to serve page-sized reads of the trailing page when the trailing page has only been partially filled.
       5              : 
       6              : use std::mem::MaybeUninit;
       7              : 
       8              : /// See module-level comment.
       9              : pub struct Buffer<const N: usize> {
      10              :     allocation: Box<[u8; N]>,
      11              :     written: usize,
      12              : }
      13              : 
      14              : impl<const N: usize> Default for Buffer<N> {
      15         1052 :     fn default() -> Self {
      16         1052 :         Self {
      17         1052 :             allocation: Box::new(
      18         1052 :                 // SAFETY: zeroed memory is a valid [u8; N]
      19         1052 :                 unsafe { MaybeUninit::zeroed().assume_init() },
      20         1052 :             ),
      21         1052 :             written: 0,
      22         1052 :         }
      23         1052 :     }
      24              : }
      25              : 
      26              : impl<const N: usize> Buffer<N> {
      27              :     #[inline(always)]
      28     20371294 :     fn invariants(&self) {
      29     20371294 :         // don't check by default, unoptimized is too expensive even for debug mode
      30     20371294 :         if false {
      31            0 :             debug_assert!(self.written <= N, "{}", self.written);
      32            0 :             debug_assert!(self.allocation[self.written..N].iter().all(|v| *v == 0));
      33     20371294 :         }
      34     20371294 :     }
      35              : 
      36       649156 :     pub fn as_zero_padded_slice(&self) -> &[u8; N] {
      37       649156 :         &self.allocation
      38       649156 :     }
      39              : }
      40              : 
      41              : impl<const N: usize> crate::virtual_file::owned_buffers_io::write::Buffer for Buffer<N> {
      42              :     type IoBuf = Self;
      43              : 
      44     20364708 :     fn cap(&self) -> usize {
      45     20364708 :         self.allocation.len()
      46     20364708 :     }
      47              : 
      48     10179061 :     fn extend_from_slice(&mut self, other: &[u8]) {
      49     10179061 :         self.invariants();
      50     10179061 :         let remaining = self.allocation.len() - self.written;
      51     10179061 :         if other.len() > remaining {
      52            0 :             panic!("calling extend_from_slice() with insufficient remaining capacity");
      53     10179061 :         }
      54     10179061 :         self.allocation[self.written..(self.written + other.len())].copy_from_slice(other);
      55     10179061 :         self.written += other.len();
      56     10179061 :         self.invariants();
      57     10179061 :     }
      58              : 
      59     40234558 :     fn pending(&self) -> usize {
      60     40234558 :         self.written
      61     40234558 :     }
      62              : 
      63         6586 :     fn flush(self) -> tokio_epoll_uring::Slice<Self> {
      64         6586 :         self.invariants();
      65         6586 :         let written = self.written;
      66         6586 :         tokio_epoll_uring::BoundedBuf::slice(self, 0..written)
      67         6586 :     }
      68              : 
      69         6586 :     fn reuse_after_flush(iobuf: Self::IoBuf) -> Self {
      70         6586 :         let Self {
      71         6586 :             mut allocation,
      72         6586 :             written,
      73         6586 :         } = iobuf;
      74         6586 :         allocation[0..written].fill(0);
      75         6586 :         let new = Self {
      76         6586 :             allocation,
      77         6586 :             written: 0,
      78         6586 :         };
      79         6586 :         new.invariants();
      80         6586 :         new
      81         6586 :     }
      82              : }
      83              : 
      84              : /// We have this trait impl so that the `flush` method in the `Buffer` impl above can produce a
      85              : /// [`tokio_epoll_uring::BoundedBuf::slice`] of the [`Self::written`] range of the data.
      86              : ///
      87              : /// Remember that bytes_init is generally _not_ a tracker of the amount
      88              : /// of valid data in the io buffer; we use `Slice` for that.
      89              : /// The `IoBuf` is _only_ for keeping track of uninitialized memory, a bit like MaybeUninit.
      90              : ///
      91              : /// SAFETY:
      92              : ///
      93              : /// The [`Self::allocation`] is stable becauses boxes are stable.
      94              : /// The memory is zero-initialized, so, bytes_init is always N.
      95              : unsafe impl<const N: usize> tokio_epoll_uring::IoBuf for Buffer<N> {
      96       102083 :     fn stable_ptr(&self) -> *const u8 {
      97       102083 :         self.allocation.as_ptr()
      98       102083 :     }
      99              : 
     100       135013 :     fn bytes_init(&self) -> usize {
     101       135013 :         // Yes, N, not self.written; Read the full comment of this impl block!
     102       135013 :         N
     103       135013 :     }
     104              : 
     105        19758 :     fn bytes_total(&self) -> usize {
     106        19758 :         N
     107        19758 :     }
     108              : }
        

Generated by: LCOV version 2.1-beta