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: 960803fca14b2e843c565dddf575f7017d250bc3.info Lines: 95.2 % 63 60
Test Date: 2024-06-22 23:41:44 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         1241 :     fn default() -> Self {
      16         1241 :         Self {
      17         1241 :             allocation: Box::new(
      18         1241 :                 // SAFETY: zeroed memory is a valid [u8; N]
      19         1241 :                 unsafe { MaybeUninit::zeroed().assume_init() },
      20         1241 :             ),
      21         1241 :             written: 0,
      22         1241 :         }
      23         1241 :     }
      24              : }
      25              : 
      26              : impl<const N: usize> Buffer<N> {
      27              :     #[inline(always)]
      28     20468874 :     fn invariants(&self) {
      29     20468874 :         // don't check by default, unoptimized is too expensive even for debug mode
      30     20468874 :         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     20468874 :         }
      34     20468874 :     }
      35              : 
      36       653349 :     pub fn as_zero_padded_slice(&self) -> &[u8; N] {
      37       653349 :         &self.allocation
      38       653349 :     }
      39              : }
      40              : 
      41              : impl<const N: usize> crate::virtual_file::owned_buffers_io::write::Buffer for Buffer<N> {
      42              :     type IoBuf = Self;
      43              : 
      44     20462264 :     fn cap(&self) -> usize {
      45     20462264 :         self.allocation.len()
      46     20462264 :     }
      47              : 
      48     10227827 :     fn extend_from_slice(&mut self, other: &[u8]) {
      49     10227827 :         self.invariants();
      50     10227827 :         let remaining = self.allocation.len() - self.written;
      51     10227827 :         if other.len() > remaining {
      52            0 :             panic!("calling extend_from_slice() with insufficient remaining capacity");
      53     10227827 :         }
      54     10227827 :         self.allocation[self.written..(self.written + other.len())].copy_from_slice(other);
      55     10227827 :         self.written += other.len();
      56     10227827 :         self.invariants();
      57     10227827 :     }
      58              : 
      59     35626706 :     fn pending(&self) -> usize {
      60     35626706 :         self.written
      61     35626706 :     }
      62              : 
      63         6610 :     fn flush(self) -> tokio_epoll_uring::Slice<Self> {
      64         6610 :         self.invariants();
      65         6610 :         let written = self.written;
      66         6610 :         tokio_epoll_uring::BoundedBuf::slice(self, 0..written)
      67         6610 :     }
      68              : 
      69         6610 :     fn reuse_after_flush(iobuf: Self::IoBuf) -> Self {
      70         6610 :         let Self {
      71         6610 :             mut allocation,
      72         6610 :             written,
      73         6610 :         } = iobuf;
      74         6610 :         allocation[0..written].fill(0);
      75         6610 :         let new = Self {
      76         6610 :             allocation,
      77         6610 :             written: 0,
      78         6610 :         };
      79         6610 :         new.invariants();
      80         6610 :         new
      81         6610 :     }
      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       102455 :     fn stable_ptr(&self) -> *const u8 {
      97       102455 :         self.allocation.as_ptr()
      98       102455 :     }
      99              : 
     100       135505 :     fn bytes_init(&self) -> usize {
     101       135505 :         // Yes, N, not self.written; Read the full comment of this impl block!
     102       135505 :         N
     103       135505 :     }
     104              : 
     105        19830 :     fn bytes_total(&self) -> usize {
     106        19830 :         N
     107        19830 :     }
     108              : }
        

Generated by: LCOV version 2.1-beta