LCOV - code coverage report
Current view: top level - libs/postgres_initdb/src - lib.rs (source / functions) Coverage Total Hit
Test: 20b6afc7b7f34578dcaab2b3acdaecfe91cd8bf1.info Lines: 0.0 % 57 0
Test Date: 2024-11-25 17:48:16 Functions: 0.0 % 3 0

            Line data    Source code
       1              : //! The canonical way we run `initdb` in Neon.
       2              : //!
       3              : //! initdb has implicit defaults that are dependent on the environment, e.g., locales & collations.
       4              : //!
       5              : //! This module's job is to eliminate the environment-dependence as much as possible.
       6              : 
       7              : use std::fmt;
       8              : 
       9              : use camino::Utf8Path;
      10              : 
      11              : pub struct RunInitdbArgs<'a> {
      12              :     pub superuser: &'a str,
      13              :     pub locale: &'a str,
      14              :     pub initdb_bin: &'a Utf8Path,
      15              :     pub pg_version: u32,
      16              :     pub library_search_path: &'a Utf8Path,
      17              :     pub pgdata: &'a Utf8Path,
      18              : }
      19              : 
      20              : #[derive(thiserror::Error, Debug)]
      21              : pub enum Error {
      22              :     Spawn(std::io::Error),
      23              :     Failed {
      24              :         status: std::process::ExitStatus,
      25              :         stderr: Vec<u8>,
      26              :     },
      27              :     WaitOutput(std::io::Error),
      28              :     Other(anyhow::Error),
      29              : }
      30              : 
      31              : impl fmt::Display for Error {
      32            0 :     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      33            0 :         match self {
      34            0 :             Error::Spawn(e) => write!(f, "Error spawning command: {:?}", e),
      35            0 :             Error::Failed { status, stderr } => write!(
      36            0 :                 f,
      37            0 :                 "Command failed with status {:?}: {}",
      38            0 :                 status,
      39            0 :                 String::from_utf8_lossy(stderr)
      40            0 :             ),
      41            0 :             Error::WaitOutput(e) => write!(f, "Error waiting for command output: {:?}", e),
      42            0 :             Error::Other(e) => write!(f, "Error: {:?}", e),
      43              :         }
      44            0 :     }
      45              : }
      46              : 
      47            0 : pub async fn do_run_initdb(args: RunInitdbArgs<'_>) -> Result<(), Error> {
      48            0 :     let RunInitdbArgs {
      49            0 :         superuser,
      50            0 :         locale,
      51            0 :         initdb_bin: initdb_bin_path,
      52            0 :         pg_version,
      53            0 :         library_search_path,
      54            0 :         pgdata,
      55            0 :     } = args;
      56            0 :     let mut initdb_command = tokio::process::Command::new(initdb_bin_path);
      57            0 :     initdb_command
      58            0 :         .args(["--pgdata", pgdata.as_ref()])
      59            0 :         .args(["--username", superuser])
      60            0 :         .args(["--encoding", "utf8"])
      61            0 :         .args(["--locale", locale])
      62            0 :         .arg("--no-instructions")
      63            0 :         .arg("--no-sync")
      64            0 :         .env_clear()
      65            0 :         .env("LD_LIBRARY_PATH", library_search_path)
      66            0 :         .env("DYLD_LIBRARY_PATH", library_search_path)
      67            0 :         .stdin(std::process::Stdio::null())
      68            0 :         // stdout invocation produces the same output every time, we don't need it
      69            0 :         .stdout(std::process::Stdio::null())
      70            0 :         // we would be interested in the stderr output, if there was any
      71            0 :         .stderr(std::process::Stdio::piped());
      72            0 : 
      73            0 :     // Before version 14, only the libc provide was available.
      74            0 :     if pg_version > 14 {
      75              :         // Version 17 brought with it a builtin locale provider which only provides
      76              :         // C and C.UTF-8. While being safer for collation purposes since it is
      77              :         // guaranteed to be consistent throughout a major release, it is also more
      78              :         // performant.
      79            0 :         let locale_provider = if pg_version >= 17 { "builtin" } else { "libc" };
      80              : 
      81            0 :         initdb_command.args(["--locale-provider", locale_provider]);
      82            0 :     }
      83              : 
      84            0 :     let initdb_proc = initdb_command.spawn().map_err(Error::Spawn)?;
      85              : 
      86              :     // Ideally we'd select here with the cancellation token, but the problem is that
      87              :     // we can't safely terminate initdb: it launches processes of its own, and killing
      88              :     // initdb doesn't kill them. After we return from this function, we want the target
      89              :     // directory to be able to be cleaned up.
      90              :     // See https://github.com/neondatabase/neon/issues/6385
      91            0 :     let initdb_output = initdb_proc
      92            0 :         .wait_with_output()
      93            0 :         .await
      94            0 :         .map_err(Error::WaitOutput)?;
      95            0 :     if !initdb_output.status.success() {
      96            0 :         return Err(Error::Failed {
      97            0 :             status: initdb_output.status,
      98            0 :             stderr: initdb_output.stderr,
      99            0 :         });
     100            0 :     }
     101            0 : 
     102            0 :     Ok(())
     103            0 : }
        

Generated by: LCOV version 2.1-beta