LCOV - code coverage report
Current view: top level - compute_tools/src - config.rs (source / functions) Coverage Total Hit
Test: e5024a5c05016c30dec7897aca22d1040a340f63.info Lines: 17.1 % 105 18
Test Date: 2024-11-20 11:45:54 Functions: 20.0 % 5 1

            Line data    Source code
       1              : use std::fs::{File, OpenOptions};
       2              : use std::io;
       3              : use std::io::prelude::*;
       4              : use std::path::Path;
       5              : 
       6              : use anyhow::Result;
       7              : 
       8              : use crate::pg_helpers::escape_conf_value;
       9              : use crate::pg_helpers::{GenericOptionExt, PgOptionsSerialize};
      10              : use compute_api::spec::{ComputeMode, ComputeSpec, GenericOption};
      11              : 
      12              : /// Check that `line` is inside a text file and put it there if it is not.
      13              : /// Create file if it doesn't exist.
      14            3 : pub fn line_in_file(path: &Path, line: &str) -> Result<bool> {
      15            3 :     let mut file = OpenOptions::new()
      16            3 :         .read(true)
      17            3 :         .write(true)
      18            3 :         .create(true)
      19            3 :         .append(false)
      20            3 :         .truncate(false)
      21            3 :         .open(path)?;
      22            3 :     let buf = io::BufReader::new(&file);
      23            3 :     let mut count: usize = 0;
      24              : 
      25            5 :     for l in buf.lines() {
      26            5 :         if l? == line {
      27            1 :             return Ok(false);
      28            4 :         }
      29            4 :         count = 1;
      30              :     }
      31              : 
      32            2 :     write!(file, "{}{}", "\n".repeat(count), line)?;
      33            2 :     Ok(true)
      34            3 : }
      35              : 
      36              : /// Create or completely rewrite configuration file specified by `path`
      37            0 : pub fn write_postgres_conf(
      38            0 :     path: &Path,
      39            0 :     spec: &ComputeSpec,
      40            0 :     extension_server_port: Option<u16>,
      41            0 : ) -> Result<()> {
      42              :     // File::create() destroys the file content if it exists.
      43            0 :     let mut file = File::create(path)?;
      44              : 
      45              :     // Write the postgresql.conf content from the spec file as is.
      46            0 :     if let Some(conf) = &spec.cluster.postgresql_conf {
      47            0 :         writeln!(file, "{}", conf)?;
      48            0 :     }
      49              : 
      50              :     // Add options for connecting to storage
      51            0 :     writeln!(file, "# Neon storage settings")?;
      52            0 :     if let Some(s) = &spec.pageserver_connstring {
      53            0 :         writeln!(file, "neon.pageserver_connstring={}", escape_conf_value(s))?;
      54            0 :     }
      55            0 :     if let Some(stripe_size) = spec.shard_stripe_size {
      56            0 :         writeln!(file, "neon.stripe_size={stripe_size}")?;
      57            0 :     }
      58            0 :     if !spec.safekeeper_connstrings.is_empty() {
      59            0 :         writeln!(
      60            0 :             file,
      61            0 :             "neon.safekeepers={}",
      62            0 :             escape_conf_value(&spec.safekeeper_connstrings.join(","))
      63            0 :         )?;
      64            0 :     }
      65            0 :     if let Some(s) = &spec.tenant_id {
      66            0 :         writeln!(file, "neon.tenant_id={}", escape_conf_value(&s.to_string()))?;
      67            0 :     }
      68            0 :     if let Some(s) = &spec.timeline_id {
      69            0 :         writeln!(
      70            0 :             file,
      71            0 :             "neon.timeline_id={}",
      72            0 :             escape_conf_value(&s.to_string())
      73            0 :         )?;
      74            0 :     }
      75              : 
      76              :     // Locales
      77            0 :     if cfg!(target_os = "macos") {
      78            0 :         writeln!(file, "lc_messages='C'")?;
      79            0 :         writeln!(file, "lc_monetary='C'")?;
      80            0 :         writeln!(file, "lc_time='C'")?;
      81            0 :         writeln!(file, "lc_numeric='C'")?;
      82              :     } else {
      83            0 :         writeln!(file, "lc_messages='C.UTF-8'")?;
      84            0 :         writeln!(file, "lc_monetary='C.UTF-8'")?;
      85            0 :         writeln!(file, "lc_time='C.UTF-8'")?;
      86            0 :         writeln!(file, "lc_numeric='C.UTF-8'")?;
      87              :     }
      88              : 
      89            0 :     match spec.mode {
      90            0 :         ComputeMode::Primary => {}
      91            0 :         ComputeMode::Static(lsn) => {
      92            0 :             // hot_standby is 'on' by default, but let's be explicit
      93            0 :             writeln!(file, "hot_standby=on")?;
      94            0 :             writeln!(file, "recovery_target_lsn='{lsn}'")?;
      95              :         }
      96              :         ComputeMode::Replica => {
      97              :             // hot_standby is 'on' by default, but let's be explicit
      98            0 :             writeln!(file, "hot_standby=on")?;
      99              :         }
     100              :     }
     101              : 
     102            0 :     if cfg!(target_os = "linux") {
     103              :         // Check /proc/sys/vm/overcommit_memory -- if it equals 2 (i.e. linux memory overcommit is
     104              :         // disabled), then the control plane has enabled swap and we should set
     105              :         // dynamic_shared_memory_type = 'mmap'.
     106              :         //
     107              :         // This is (maybe?) temporary - for more, see https://github.com/neondatabase/cloud/issues/12047.
     108            0 :         let overcommit_memory_contents = std::fs::read_to_string("/proc/sys/vm/overcommit_memory")
     109            0 :             // ignore any errors - they may be expected to occur under certain situations (e.g. when
     110            0 :             // not running in Linux).
     111            0 :             .unwrap_or_else(|_| String::new());
     112            0 :         if overcommit_memory_contents.trim() == "2" {
     113            0 :             let opt = GenericOption {
     114            0 :                 name: "dynamic_shared_memory_type".to_owned(),
     115            0 :                 value: Some("mmap".to_owned()),
     116            0 :                 vartype: "enum".to_owned(),
     117            0 :             };
     118            0 : 
     119            0 :             write!(file, "{}", opt.to_pg_setting())?;
     120            0 :         }
     121            0 :     }
     122              : 
     123              :     // If there are any extra options in the 'settings' field, append those
     124            0 :     if spec.cluster.settings.is_some() {
     125            0 :         writeln!(file, "# Managed by compute_ctl: begin")?;
     126            0 :         write!(file, "{}", spec.cluster.settings.as_pg_settings())?;
     127            0 :         writeln!(file, "# Managed by compute_ctl: end")?;
     128            0 :     }
     129              : 
     130            0 :     if let Some(port) = extension_server_port {
     131            0 :         writeln!(file, "neon.extension_server_port={}", port)?;
     132            0 :     }
     133              : 
     134              :     // This is essential to keep this line at the end of the file,
     135              :     // because it is intended to override any settings above.
     136            0 :     writeln!(file, "include_if_exists = 'compute_ctl_temp_override.conf'")?;
     137              : 
     138            0 :     Ok(())
     139            0 : }
     140              : 
     141            0 : pub fn with_compute_ctl_tmp_override<F>(pgdata_path: &Path, options: &str, exec: F) -> Result<()>
     142            0 : where
     143            0 :     F: FnOnce() -> Result<()>,
     144            0 : {
     145            0 :     let path = pgdata_path.join("compute_ctl_temp_override.conf");
     146            0 :     let mut file = File::create(path)?;
     147            0 :     write!(file, "{}", options)?;
     148              : 
     149            0 :     let res = exec();
     150            0 : 
     151            0 :     file.set_len(0)?;
     152              : 
     153            0 :     res
     154            0 : }
        

Generated by: LCOV version 2.1-beta