LCOV - code coverage report
Current view: top level - pageserver/src/virtual_file/owned_buffers_io/aligned_buffer - raw.rs (source / functions) Coverage Total Hit
Test: 5445d246133daeceb0507e6cc0797ab7c1c70cb8.info Lines: 89.5 % 105 94
Test Date: 2025-03-12 18:05:02 Functions: 90.0 % 30 27

            Line data    Source code
       1              : use core::slice;
       2              : use std::alloc::{self, Layout};
       3              : use std::cmp;
       4              : use std::mem::ManuallyDrop;
       5              : 
       6              : use super::alignment::{Alignment, ConstAlign};
       7              : 
       8              : #[derive(Debug)]
       9              : struct AlignedBufferPtr(*mut u8);
      10              : 
      11              : // SAFETY: We gurantees no one besides `IoBufferPtr` itself has the raw pointer.
      12              : unsafe impl Send for AlignedBufferPtr {}
      13              : 
      14              : // SAFETY: We gurantees no one besides `IoBufferPtr` itself has the raw pointer.
      15              : unsafe impl Sync for AlignedBufferPtr {}
      16              : 
      17              : /// An aligned buffer type.
      18              : #[derive(Debug)]
      19              : pub struct RawAlignedBuffer<A: Alignment> {
      20              :     ptr: AlignedBufferPtr,
      21              :     capacity: usize,
      22              :     len: usize,
      23              :     align: A,
      24              : }
      25              : 
      26              : impl<const A: usize> RawAlignedBuffer<ConstAlign<A>> {
      27              :     /// Constructs a new, empty `IoBufferMut` with at least the specified capacity and alignment.
      28              :     ///
      29              :     /// The buffer will be able to hold at most `capacity` elements and will never resize.
      30              :     ///
      31              :     ///
      32              :     /// # Panics
      33              :     ///
      34              :     /// Panics if the new capacity exceeds `isize::MAX` _bytes_, or if the following alignment requirement is not met:
      35              :     /// * `align` must not be zero,
      36              :     ///
      37              :     /// * `align` must be a power of two,
      38              :     ///
      39              :     /// * `capacity`, when rounded up to the nearest multiple of `align`,
      40              :     ///    must not overflow isize (i.e., the rounded value must be
      41              :     ///    less than or equal to `isize::MAX`).
      42      1440478 :     pub fn with_capacity(capacity: usize) -> Self {
      43      1440478 :         let align = ConstAlign::<A>;
      44      1440478 :         let layout = Layout::from_size_align(capacity, align.align()).expect("Invalid layout");
      45              : 
      46              :         // SAFETY:  Making an allocation with a sized and aligned layout. The memory is manually freed with the same layout.
      47      1440478 :         let ptr = unsafe {
      48      1440478 :             let ptr = alloc::alloc(layout);
      49      1440478 :             if ptr.is_null() {
      50            0 :                 alloc::handle_alloc_error(layout);
      51      1440478 :             }
      52      1440478 :             AlignedBufferPtr(ptr)
      53      1440478 :         };
      54      1440478 : 
      55      1440478 :         RawAlignedBuffer {
      56      1440478 :             ptr,
      57      1440478 :             capacity,
      58      1440478 :             len: 0,
      59      1440478 :             align,
      60      1440478 :         }
      61      1440478 :     }
      62              : }
      63              : 
      64              : impl<A: Alignment> RawAlignedBuffer<A> {
      65              :     /// Returns the total number of bytes the buffer can hold.
      66              :     #[inline]
      67     74389123 :     pub fn capacity(&self) -> usize {
      68     74389123 :         self.capacity
      69     74389123 :     }
      70              : 
      71              :     /// Returns the alignment of the buffer.
      72              :     #[inline]
      73           68 :     pub fn align(&self) -> usize {
      74           68 :         self.align.align()
      75           68 :     }
      76              : 
      77              :     /// Returns the number of bytes in the buffer, also referred to as its 'length'.
      78              :     #[inline]
      79     95047371 :     pub fn len(&self) -> usize {
      80     95047371 :         self.len
      81     95047371 :     }
      82              : 
      83              :     /// Force the length of the buffer to `new_len`.
      84              :     #[inline]
      85     11062586 :     pub unsafe fn set_len(&mut self, new_len: usize) {
      86     11062586 :         debug_assert!(new_len <= self.capacity());
      87     11062586 :         self.len = new_len;
      88     11062586 :     }
      89              : 
      90              :     #[inline]
      91     77111546 :     pub fn as_ptr(&self) -> *const u8 {
      92     77111546 :         self.ptr.0
      93     77111546 :     }
      94              : 
      95              :     #[inline]
      96     14381085 :     pub fn as_mut_ptr(&mut self) -> *mut u8 {
      97     14381085 :         self.ptr.0
      98     14381085 :     }
      99              : 
     100              :     /// Extracts a slice containing the entire buffer.
     101              :     ///
     102              :     /// Equivalent to `&s[..]`.
     103              :     #[inline]
     104      8367887 :     pub fn as_slice(&self) -> &[u8] {
     105      8367887 :         // SAFETY: The pointer is valid and `len` bytes are initialized.
     106      8367887 :         unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
     107      8367887 :     }
     108              : 
     109              :     /// Extracts a mutable slice of the entire buffer.
     110              :     ///
     111              :     /// Equivalent to `&mut s[..]`.
     112            0 :     pub fn as_mut_slice(&mut self) -> &mut [u8] {
     113            0 :         // SAFETY: The pointer is valid and `len` bytes are initialized.
     114            0 :         unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
     115            0 :     }
     116              : 
     117              :     /// Drops the all the contents of the buffer, setting its length to `0`.
     118              :     #[inline]
     119        13298 :     pub fn clear(&mut self) {
     120        13298 :         self.len = 0;
     121        13298 :     }
     122              : 
     123              :     /// Reserves capacity for at least `additional` more bytes to be inserted
     124              :     /// in the given `IoBufferMut`. The collection may reserve more space to
     125              :     /// speculatively avoid frequent reallocations. After calling `reserve`,
     126              :     /// capacity will be greater than or equal to `self.len() + additional`.
     127              :     /// Does nothing if capacity is already sufficient.
     128              :     ///
     129              :     /// # Panics
     130              :     ///
     131              :     /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     132      9623144 :     pub fn reserve(&mut self, additional: usize) {
     133      9623144 :         if additional > self.capacity() - self.len() {
     134           12 :             self.reserve_inner(additional);
     135      9623132 :         }
     136      9623144 :     }
     137              : 
     138           12 :     fn reserve_inner(&mut self, additional: usize) {
     139           12 :         let Some(required_cap) = self.len().checked_add(additional) else {
     140            0 :             capacity_overflow()
     141              :         };
     142              : 
     143           12 :         let old_capacity = self.capacity();
     144           12 :         let align = self.align();
     145           12 :         // This guarantees exponential growth. The doubling cannot overflow
     146           12 :         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
     147           12 :         let cap = cmp::max(old_capacity * 2, required_cap);
     148           12 : 
     149           12 :         if !is_valid_alloc(cap) {
     150            0 :             capacity_overflow()
     151           12 :         }
     152           12 :         let new_layout = Layout::from_size_align(cap, self.align()).expect("Invalid layout");
     153           12 : 
     154           12 :         let old_ptr = self.as_mut_ptr();
     155              : 
     156              :         // SAFETY: old allocation was allocated with std::alloc::alloc with the same layout,
     157              :         // and we panics on null pointer.
     158           12 :         let (ptr, cap) = unsafe {
     159           12 :             let old_layout = Layout::from_size_align_unchecked(old_capacity, align);
     160           12 :             let ptr = alloc::realloc(old_ptr, old_layout, new_layout.size());
     161           12 :             if ptr.is_null() {
     162            0 :                 alloc::handle_alloc_error(new_layout);
     163           12 :             }
     164           12 :             (AlignedBufferPtr(ptr), cap)
     165           12 :         };
     166           12 : 
     167           12 :         self.ptr = ptr;
     168           12 :         self.capacity = cap;
     169           12 :     }
     170              : 
     171              :     /// Shortens the buffer, keeping the first len bytes.
     172           20 :     pub fn truncate(&mut self, len: usize) {
     173           20 :         if len > self.len {
     174            0 :             return;
     175           20 :         }
     176           20 :         self.len = len;
     177           20 :     }
     178              : 
     179              :     /// Consumes and leaks the `IoBufferMut`, returning a mutable reference to the contents, &'a mut [u8].
     180          188 :     pub fn leak<'a>(self) -> &'a mut [u8] {
     181          188 :         let mut buf = ManuallyDrop::new(self);
     182          188 :         // SAFETY: leaking the buffer as intended.
     183          188 :         unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len) }
     184          188 :     }
     185              : }
     186              : 
     187            0 : fn capacity_overflow() -> ! {
     188            0 :     panic!("capacity overflow")
     189              : }
     190              : 
     191              : // We need to guarantee the following:
     192              : // * We don't ever allocate `> isize::MAX` byte-size objects.
     193              : // * We don't overflow `usize::MAX` and actually allocate too little.
     194              : //
     195              : // On 64-bit we just need to check for overflow since trying to allocate
     196              : // `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add
     197              : // an extra guard for this in case we're running on a platform which can use
     198              : // all 4GB in user-space, e.g., PAE or x32.
     199              : #[inline]
     200           12 : fn is_valid_alloc(alloc_size: usize) -> bool {
     201           12 :     !(usize::BITS < 64 && alloc_size > isize::MAX as usize)
     202           12 : }
     203              : 
     204              : impl<A: Alignment> Drop for RawAlignedBuffer<A> {
     205      1439802 :     fn drop(&mut self) {
     206      1439802 :         // SAFETY: memory was allocated with std::alloc::alloc with the same layout.
     207      1439802 :         unsafe {
     208      1439802 :             alloc::dealloc(
     209      1439802 :                 self.as_mut_ptr(),
     210      1439802 :                 Layout::from_size_align_unchecked(self.capacity, self.align.align()),
     211      1439802 :             )
     212      1439802 :         }
     213      1439802 :     }
     214              : }
        

Generated by: LCOV version 2.1-beta