LCOV - code coverage report
Current view: top level - pageserver/src/virtual_file - temporary.rs (source / functions) Coverage Total Hit
Test: aca806cab4756d7eb6a304846130f4a73a5d5393.info Lines: 85.7 % 49 42
Test Date: 2025-04-24 20:31:15 Functions: 87.5 % 8 7

            Line data    Source code
       1              : use tracing::error;
       2              : use utils::sync::gate::GateGuard;
       3              : 
       4              : use crate::context::RequestContext;
       5              : 
       6              : use super::{
       7              :     MaybeFatalIo, VirtualFile,
       8              :     owned_buffers_io::{
       9              :         io_buf_aligned::IoBufAligned, io_buf_ext::FullSlice, write::OwnedAsyncWriter,
      10              :     },
      11              : };
      12              : 
      13              : /// A wrapper around [`super::VirtualFile`] that deletes the file on drop.
      14              : /// For use as a [`OwnedAsyncWriter`] in [`super::owned_buffers_io::write::BufferedWriter`].
      15              : #[derive(Debug)]
      16              : pub struct TempVirtualFile {
      17              :     inner: Option<Inner>,
      18              : }
      19              : 
      20              : #[derive(Debug)]
      21              : struct Inner {
      22              :     file: VirtualFile,
      23              :     /// Gate guard is held on as long as we need to do operations in the path (delete on drop)
      24              :     _gate_guard: GateGuard,
      25              : }
      26              : 
      27              : impl OwnedAsyncWriter for TempVirtualFile {
      28       141492 :     fn write_all_at<Buf: IoBufAligned + Send>(
      29       141492 :         &self,
      30       141492 :         buf: FullSlice<Buf>,
      31       141492 :         offset: u64,
      32       141492 :         ctx: &RequestContext,
      33       141492 :     ) -> impl std::future::Future<Output = (FullSlice<Buf>, std::io::Result<()>)> + Send {
      34       141492 :         VirtualFile::write_all_at(self, buf, offset, ctx)
      35       141492 :     }
      36              : 
      37           84 :     async fn set_len(&self, len: u64, ctx: &RequestContext) -> std::io::Result<()> {
      38           84 :         VirtualFile::set_len(self, len, ctx).await
      39           84 :     }
      40              : }
      41              : 
      42              : impl Drop for TempVirtualFile {
      43        20004 :     fn drop(&mut self) {
      44        20004 :         let Some(Inner { file, _gate_guard }) = self.inner.take() else {
      45        11208 :             return;
      46              :         };
      47         8796 :         let path = file.path();
      48           12 :         if let Err(e) =
      49         8796 :             std::fs::remove_file(path).maybe_fatal_err("failed to remove the virtual file")
      50              :         {
      51           12 :             error!(err=%e, path=%path, "failed to remove");
      52         8784 :         }
      53         8796 :         drop(_gate_guard);
      54        20004 :     }
      55              : }
      56              : 
      57              : impl std::ops::Deref for TempVirtualFile {
      58              :     type Target = VirtualFile;
      59              : 
      60       483298 :     fn deref(&self) -> &Self::Target {
      61       483298 :         &self
      62       483298 :             .inner
      63       483298 :             .as_ref()
      64       483298 :             .expect("only None after into_inner or drop")
      65       483298 :             .file
      66       483298 :     }
      67              : }
      68              : 
      69              : impl std::ops::DerefMut for TempVirtualFile {
      70            0 :     fn deref_mut(&mut self) -> &mut Self::Target {
      71            0 :         &mut self
      72            0 :             .inner
      73            0 :             .as_mut()
      74            0 :             .expect("only None after into_inner or drop")
      75            0 :             .file
      76            0 :     }
      77              : }
      78              : 
      79              : impl TempVirtualFile {
      80              :     /// The caller is responsible for ensuring that the path of `virtual_file` is not reused
      81              :     /// until after this TempVirtualFile's `Drop` impl has completed.
      82              :     /// Failure to do so will result in unlinking of the reused path by the original instance's Drop impl.
      83              :     /// The best way to do so is by using a monotonic counter as a disambiguator.
      84              :     /// TODO: centralize this disambiguator pattern inside this struct.
      85              :     ///   => <https://github.com/neondatabase/neon/pull/11549#issuecomment-2824592831>
      86        20784 :     pub fn new(virtual_file: VirtualFile, gate_guard: GateGuard) -> Self {
      87        20784 :         Self {
      88        20784 :             inner: Some(Inner {
      89        20784 :                 file: virtual_file,
      90        20784 :                 _gate_guard: gate_guard,
      91        20784 :             }),
      92        20784 :         }
      93        20784 :     }
      94              : 
      95              :     /// Dismantle this wrapper and return the underlying [`VirtualFile`].
      96              :     /// This disables auto-unlinking functionality that is the essence of this wrapper.
      97              :     ///
      98              :     /// The gate guard is dropped as well; it is the callers responsibility to ensure filesystem
      99              :     /// operations after calls to this functions are still gated by some other gate guard.
     100              :     ///
     101              :     /// TODO:
     102              :     /// - centralize the common usage pattern of callers (sync_all(self), rename(self, dst), sync_all(dst.parent))
     103              :     ///   => <https://github.com/neondatabase/neon/pull/11549#issuecomment-2824592831>
     104        11208 :     pub fn disarm_into_inner(mut self) -> VirtualFile {
     105        11208 :         self.inner
     106        11208 :             .take()
     107        11208 :             .expect("only None after into_inner or drop, and we are into_inner, and we consume")
     108        11208 :             .file
     109        11208 :     }
     110              : }
        

Generated by: LCOV version 2.1-beta