LCOV - code coverage report
Current view: top level - pageserver/src/virtual_file - open_options.rs (source / functions) Coverage Total Hit
Test: 1e20c4f2b28aa592527961bb32170ebbd2c9172f.info Lines: 69.1 % 110 76
Test Date: 2025-07-16 12:29:03 Functions: 82.4 % 17 14

            Line data    Source code
       1              : //! Enum-dispatch to the `OpenOptions` type of the respective [`super::IoEngineKind`];
       2              : 
       3              : use std::os::fd::OwnedFd;
       4              : use std::os::unix::fs::OpenOptionsExt;
       5              : use std::path::Path;
       6              : 
       7              : use super::io_engine::IoEngine;
       8              : 
       9              : #[derive(Debug, Clone)]
      10              : pub struct OpenOptions {
      11              :     /// We keep a copy of the write() flag we pass to the `inner`` `OptionOptions`
      12              :     /// to support [`Self::is_write`].
      13              :     write: bool,
      14              :     /// We don't expose + pass through a raw `custom_flags()` style API.
      15              :     /// The only custom flag we support is `O_DIRECT`, which we track here
      16              :     /// and map to `custom_flags()` in the [`Self::open`] method.
      17              :     direct: bool,
      18              :     inner: Inner,
      19              : }
      20              : #[derive(Debug, Clone)]
      21              : enum Inner {
      22              :     StdFs(std::fs::OpenOptions),
      23              :     #[cfg(target_os = "linux")]
      24              :     TokioEpollUring(tokio_epoll_uring::ops::open_at::OpenOptions),
      25              : }
      26              : 
      27              : impl Default for OpenOptions {
      28         3170 :     fn default() -> Self {
      29         3170 :         let inner = match super::io_engine::get() {
      30            0 :             IoEngine::NotSet => panic!("io engine not set"),
      31            0 :             IoEngine::StdFs => Inner::StdFs(std::fs::OpenOptions::new()),
      32              :             #[cfg(target_os = "linux")]
      33              :             IoEngine::TokioEpollUring => {
      34         3170 :                 Inner::TokioEpollUring(tokio_epoll_uring::ops::open_at::OpenOptions::new())
      35              :             }
      36              :         };
      37         3170 :         Self {
      38         3170 :             write: false,
      39         3170 :             direct: false,
      40         3170 :             inner,
      41         3170 :         }
      42         3170 :     }
      43              : }
      44              : 
      45              : impl OpenOptions {
      46         3170 :     pub fn new() -> OpenOptions {
      47         3170 :         Self::default()
      48         3170 :     }
      49              : 
      50         2654 :     pub(super) fn is_write(&self) -> bool {
      51         2654 :         self.write
      52         2654 :     }
      53              : 
      54       298390 :     pub(super) fn is_direct(&self) -> bool {
      55       298390 :         self.direct
      56       298390 :     }
      57              : 
      58         2034 :     pub fn read(mut self, read: bool) -> Self {
      59         2034 :         match &mut self.inner {
      60            0 :             Inner::StdFs(x) => {
      61            0 :                 let _ = x.read(read);
      62            0 :             }
      63              :             #[cfg(target_os = "linux")]
      64         2034 :             Inner::TokioEpollUring(x) => {
      65         2034 :                 let _ = x.read(read);
      66         2034 :             }
      67              :         }
      68         2034 :         self
      69         2034 :     }
      70              : 
      71         1807 :     pub fn write(mut self, write: bool) -> Self {
      72         1807 :         self.write = write;
      73         1807 :         match &mut self.inner {
      74            0 :             Inner::StdFs(x) => {
      75            0 :                 let _ = x.write(write);
      76            0 :             }
      77              :             #[cfg(target_os = "linux")]
      78         1807 :             Inner::TokioEpollUring(x) => {
      79         1807 :                 let _ = x.write(write);
      80         1807 :             }
      81              :         }
      82         1807 :         self
      83         1807 :     }
      84              : 
      85         3172 :     pub fn create(mut self, create: bool) -> Self {
      86         3172 :         match &mut self.inner {
      87            0 :             Inner::StdFs(x) => {
      88            0 :                 let _ = x.create(create);
      89            0 :             }
      90              :             #[cfg(target_os = "linux")]
      91         3172 :             Inner::TokioEpollUring(x) => {
      92         3172 :                 let _ = x.create(create);
      93         3172 :             }
      94              :         }
      95         3172 :         self
      96         3172 :     }
      97              : 
      98         4975 :     pub fn create_new(mut self, create_new: bool) -> Self {
      99         4975 :         match &mut self.inner {
     100            0 :             Inner::StdFs(x) => {
     101            0 :                 let _ = x.create_new(create_new);
     102            0 :             }
     103              :             #[cfg(target_os = "linux")]
     104         4975 :             Inner::TokioEpollUring(x) => {
     105         4975 :                 let _ = x.create_new(create_new);
     106         4975 :             }
     107              :         }
     108         4975 :         self
     109         4975 :     }
     110              : 
     111         3172 :     pub fn truncate(mut self, truncate: bool) -> Self {
     112         3172 :         match &mut self.inner {
     113            0 :             Inner::StdFs(x) => {
     114            0 :                 let _ = x.truncate(truncate);
     115            0 :             }
     116              :             #[cfg(target_os = "linux")]
     117         3172 :             Inner::TokioEpollUring(x) => {
     118         3172 :                 let _ = x.truncate(truncate);
     119         3172 :             }
     120              :         }
     121         3172 :         self
     122         3172 :     }
     123              : 
     124              :     /// Don't use, `O_APPEND` is not supported.
     125            0 :     pub fn append(&mut self, _append: bool) {
     126            0 :         super::io_engine::panic_operation_must_be_idempotent();
     127            0 :     }
     128              : 
     129        99022 :     pub(in crate::virtual_file) async fn open(&self, path: &Path) -> std::io::Result<OwnedFd> {
     130              :         #[cfg_attr(not(target_os = "linux"), allow(unused_mut))]
     131        99022 :         let mut custom_flags = 0;
     132        99022 :         if self.direct {
     133              :             #[cfg(target_os = "linux")]
     134        98506 :             {
     135        98506 :                 custom_flags |= nix::libc::O_DIRECT;
     136        98506 :             }
     137              :             #[cfg(not(target_os = "linux"))]
     138              :             {
     139              :                 // Other platforms may be used for development but don't necessarily have a 1:1 equivalent to Linux's O_DIRECT (macOS!).
     140              :                 // Just don't set the flag; to catch alignment bugs typical for O_DIRECT,
     141              :                 // we have a runtime validation layer inside `VirtualFile::write_at` and `VirtualFile::read_at`.
     142              :                 static WARNING: std::sync::Once = std::sync::Once::new();
     143              :                 WARNING.call_once(|| {
     144              :                     let span = tracing::info_span!(parent: None, "open_options");
     145              :                     let _enter = span.enter();
     146              :                     tracing::warn!("your platform is not a supported production platform, ignoing request for O_DIRECT; this could hide alignment bugs; this warning is logged once per process");
     147              :                 });
     148              :             }
     149          516 :         }
     150              : 
     151        99022 :         match self.inner.clone() {
     152            0 :             Inner::StdFs(mut x) => x
     153            0 :                 .custom_flags(custom_flags)
     154            0 :                 .open(path)
     155            0 :                 .map(|file| file.into()),
     156              :             #[cfg(target_os = "linux")]
     157        99022 :             Inner::TokioEpollUring(mut x) => {
     158        99022 :                 x.custom_flags(custom_flags);
     159        99022 :                 let system = super::io_engine::tokio_epoll_uring_ext::thread_local_system().await;
     160        99022 :                 let (_, res) = super::io_engine::retry_ecanceled_once((), |()| async {
     161        99022 :                     let res = system.open(path, &x).await;
     162        99022 :                     ((), res)
     163       198044 :                 })
     164        99022 :                 .await;
     165        99022 :                 res.map_err(super::io_engine::epoll_uring_error_to_std)
     166              :             }
     167              :         }
     168        99022 :     }
     169              : 
     170            0 :     pub fn mode(mut self, mode: u32) -> Self {
     171            0 :         match &mut self.inner {
     172            0 :             Inner::StdFs(x) => {
     173            0 :                 let _ = x.mode(mode);
     174            0 :             }
     175              :             #[cfg(target_os = "linux")]
     176            0 :             Inner::TokioEpollUring(x) => {
     177            0 :                 let _ = x.mode(mode);
     178            0 :             }
     179              :         }
     180            0 :         self
     181            0 :     }
     182              : 
     183         2654 :     pub fn direct(mut self, direct: bool) -> Self {
     184         2654 :         self.direct = direct;
     185         2654 :         self
     186         2654 :     }
     187              : }
        

Generated by: LCOV version 2.1-beta