LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - config.rs (source / functions) Coverage Total Hit
Test: 1e20c4f2b28aa592527961bb32170ebbd2c9172f.info Lines: 69.7 % 231 161
Test Date: 2025-07-16 12:29:03 Functions: 5.7 % 87 5

            Line data    Source code
       1              : use camino::Utf8PathBuf;
       2              : 
       3              : #[cfg(test)]
       4              : mod tests;
       5              : 
       6              : use const_format::formatcp;
       7              : use posthog_client_lite::PostHogClientConfig;
       8              : use utils::serde_percent::Percent;
       9              : pub const DEFAULT_PG_LISTEN_PORT: u16 = 64000;
      10              : pub const DEFAULT_PG_LISTEN_ADDR: &str = formatcp!("127.0.0.1:{DEFAULT_PG_LISTEN_PORT}");
      11              : pub const DEFAULT_HTTP_LISTEN_PORT: u16 = 9898;
      12              : pub const DEFAULT_HTTP_LISTEN_ADDR: &str = formatcp!("127.0.0.1:{DEFAULT_HTTP_LISTEN_PORT}");
      13              : // TODO: gRPC is disabled by default for now, but the port is used in neon_local.
      14              : pub const DEFAULT_GRPC_LISTEN_PORT: u16 = 51051; // storage-broker already uses 50051
      15              : 
      16              : use std::collections::HashMap;
      17              : use std::fmt::Display;
      18              : use std::num::{NonZeroU64, NonZeroUsize};
      19              : use std::str::FromStr;
      20              : use std::time::Duration;
      21              : 
      22              : use postgres_backend::AuthType;
      23              : use remote_storage::RemoteStorageConfig;
      24              : use serde_with::serde_as;
      25              : use utils::logging::LogFormat;
      26              : 
      27              : use crate::models::{ImageCompressionAlgorithm, LsnLease};
      28              : 
      29              : // Certain metadata (e.g. externally-addressable name, AZ) is delivered
      30              : // as a separate structure.  This information is not needed by the pageserver
      31              : // itself, it is only used for registering the pageserver with the control
      32              : // plane and/or storage controller.
      33            0 : #[derive(PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
      34              : pub struct NodeMetadata {
      35              :     #[serde(rename = "host")]
      36              :     pub postgres_host: String,
      37              :     #[serde(rename = "port")]
      38              :     pub postgres_port: u16,
      39              :     pub grpc_host: Option<String>,
      40              :     pub grpc_port: Option<u16>,
      41              :     pub http_host: String,
      42              :     pub http_port: u16,
      43              :     pub https_port: Option<u16>,
      44              : 
      45              :     // Deployment tools may write fields to the metadata file beyond what we
      46              :     // use in this type: this type intentionally only names fields that require.
      47              :     #[serde(flatten)]
      48              :     pub other: HashMap<String, serde_json::Value>,
      49              : }
      50              : 
      51              : impl Display for NodeMetadata {
      52            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      53            0 :         write!(
      54            0 :             f,
      55            0 :             "postgresql://{}:{} ",
      56              :             self.postgres_host, self.postgres_port
      57            0 :         )?;
      58            0 :         if let Some(grpc_host) = &self.grpc_host {
      59            0 :             let grpc_port = self.grpc_port.unwrap_or_default();
      60            0 :             write!(f, "grpc://{grpc_host}:{grpc_port} ")?;
      61            0 :         }
      62            0 :         write!(f, "http://{}:{} ", self.http_host, self.http_port)?;
      63            0 :         write!(f, "other:{:?}", self.other)?;
      64            0 :         Ok(())
      65            0 :     }
      66              : }
      67              : 
      68              : /// PostHog integration config. This is used in pageserver, storcon, and neon_local.
      69              : /// Ensure backward compatibility when adding new fields.
      70              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
      71              : pub struct PostHogConfig {
      72              :     /// PostHog project ID
      73              :     #[serde(default)]
      74              :     #[serde(skip_serializing_if = "Option::is_none")]
      75              :     pub project_id: Option<String>,
      76              :     /// Server-side (private) API key
      77              :     #[serde(default)]
      78              :     #[serde(skip_serializing_if = "Option::is_none")]
      79              :     pub server_api_key: Option<String>,
      80              :     /// Client-side (public) API key
      81              :     #[serde(default)]
      82              :     #[serde(skip_serializing_if = "Option::is_none")]
      83              :     pub client_api_key: Option<String>,
      84              :     /// Private API URL
      85              :     #[serde(default)]
      86              :     #[serde(skip_serializing_if = "Option::is_none")]
      87              :     pub private_api_url: Option<String>,
      88              :     /// Public API URL
      89              :     #[serde(default)]
      90              :     #[serde(skip_serializing_if = "Option::is_none")]
      91              :     pub public_api_url: Option<String>,
      92              :     /// Refresh interval for the feature flag spec.
      93              :     /// The storcon will push the feature flag spec to the pageserver. If the pageserver does not receive
      94              :     /// the spec for `refresh_interval`, it will fetch the spec from the PostHog API.
      95              :     #[serde(default)]
      96              :     #[serde(skip_serializing_if = "Option::is_none")]
      97              :     #[serde(with = "humantime_serde")]
      98              :     pub refresh_interval: Option<Duration>,
      99              : }
     100              : 
     101              : impl PostHogConfig {
     102            0 :     pub fn try_into_posthog_config(self) -> Result<PostHogClientConfig, &'static str> {
     103            0 :         let Some(project_id) = self.project_id else {
     104            0 :             return Err("project_id is required");
     105              :         };
     106            0 :         let Some(server_api_key) = self.server_api_key else {
     107            0 :             return Err("server_api_key is required");
     108              :         };
     109            0 :         let Some(client_api_key) = self.client_api_key else {
     110            0 :             return Err("client_api_key is required");
     111              :         };
     112            0 :         let Some(private_api_url) = self.private_api_url else {
     113            0 :             return Err("private_api_url is required");
     114              :         };
     115            0 :         let Some(public_api_url) = self.public_api_url else {
     116            0 :             return Err("public_api_url is required");
     117              :         };
     118            0 :         Ok(PostHogClientConfig {
     119            0 :             project_id,
     120            0 :             server_api_key,
     121            0 :             client_api_key,
     122            0 :             private_api_url,
     123            0 :             public_api_url,
     124            0 :         })
     125            0 :     }
     126              : }
     127              : 
     128              : /// `pageserver.toml`
     129              : ///
     130              : /// We use serde derive with `#[serde(default)]` to generate a deserializer
     131              : /// that fills in the default values for each config field.
     132              : ///
     133              : /// If there cannot be a static default value because we need to make runtime
     134              : /// checks to determine the default, make it an `Option` (which defaults to None).
     135              : /// The runtime check should be done in the consuming crate, i.e., `pageserver`.
     136              : ///
     137              : /// Unknown fields are silently ignored during deserialization.
     138              : /// The alternative, which we used in the past, was to set `deny_unknown_fields`,
     139              : /// which fails deserialization, and hence pageserver startup, if there is an unknown field.
     140              : /// The reason we don't do that anymore is that it complicates
     141              : /// usage of config fields for feature flagging, which we commonly do for
     142              : /// region-by-region rollouts.
     143              : /// The complications mainly arise because the `pageserver.toml` contents on a
     144              : /// prod server have a separate lifecycle from the pageserver binary.
     145              : /// For instance, `pageserver.toml` contents today are defined in the internal
     146              : /// infra repo, and thus introducing a new config field to pageserver and
     147              : /// rolling it out to prod servers are separate commits in separate repos
     148              : /// that can't be made or rolled back atomically.
     149              : /// Rollbacks in particular pose a risk with deny_unknown_fields because
     150              : /// the old pageserver binary may reject a new config field, resulting in
     151              : /// an outage unless the person doing the pageserver rollback remembers
     152              : /// to also revert the commit that added the config field in to the
     153              : /// `pageserver.toml` templates in the internal infra repo.
     154              : /// (A pre-deploy config check would eliminate this risk during rollbacks,
     155              : ///  cf [here](https://github.com/neondatabase/cloud/issues/24349).)
     156              : /// In addition to this compatibility problem during emergency rollbacks,
     157              : /// deny_unknown_fields adds further complications when decomissioning a feature
     158              : /// flag: with deny_unknown_fields, we can't remove a flag from the [`ConfigToml`]
     159              : /// until all prod servers' `pageserver.toml` files have been updated to a version
     160              : /// that doesn't specify the flag. Otherwise new software would fail to start up.
     161              : /// This adds the requirement for an intermediate step where the new config field
     162              : /// is accepted but ignored, prolonging the decomissioning process by an entire
     163              : /// release cycle.
     164              : /// By contrast  with unknown fields silently ignored, decomissioning a feature
     165              : /// flag is a one-step process: we can skip the intermediate step and straight
     166              : /// remove the field from the [`ConfigToml`]. We leave the field in the
     167              : /// `pageserver.toml` files on prod servers until we reach certainty that we
     168              : /// will not roll back to old software whose behavior was dependent on config.
     169              : /// Then we can remove the field from the templates in the internal infra repo.
     170              : /// This process is [documented internally](
     171              : /// https://docs.neon.build/storage/pageserver_configuration.html).
     172              : ///
     173              : /// Note that above relaxed compatbility for the config format does NOT APPLY
     174              : /// TO THE STORAGE FORMAT. As general guidance, when introducing storage format
     175              : /// changes, ensure that the potential rollback target version will be compatible
     176              : /// with the new format. This must hold regardless of what flags are set in in the `pageserver.toml`:
     177              : /// any format version that exists in an environment must be compatible with the software that runs there.
     178              : /// Use a pageserver.toml flag only to gate whether software _writes_ the new format.
     179              : /// For more compatibility considerations, refer to [internal docs](
     180              : /// https://docs.neon.build/storage/compat.html?highlight=compat#format-versions--compatibility)
     181              : #[serde_as]
     182              : #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
     183              : #[serde(default)]
     184              : pub struct ConfigToml {
     185              :     // types mapped 1:1 into the runtime PageServerConfig type
     186              :     pub listen_pg_addr: String,
     187              :     pub listen_http_addr: String,
     188              :     pub listen_https_addr: Option<String>,
     189              :     pub listen_grpc_addr: Option<String>,
     190              :     pub ssl_key_file: Utf8PathBuf,
     191              :     pub ssl_cert_file: Utf8PathBuf,
     192              :     #[serde(with = "humantime_serde")]
     193              :     pub ssl_cert_reload_period: Duration,
     194              :     pub ssl_ca_file: Option<Utf8PathBuf>,
     195              :     pub availability_zone: Option<String>,
     196              :     #[serde(with = "humantime_serde")]
     197              :     pub wait_lsn_timeout: Duration,
     198              :     #[serde(with = "humantime_serde")]
     199              :     pub wal_redo_timeout: Duration,
     200              :     pub superuser: String,
     201              :     pub locale: String,
     202              :     pub page_cache_size: usize,
     203              :     pub max_file_descriptors: usize,
     204              :     pub pg_distrib_dir: Option<Utf8PathBuf>,
     205              :     #[serde_as(as = "serde_with::DisplayFromStr")]
     206              :     pub http_auth_type: AuthType,
     207              :     #[serde_as(as = "serde_with::DisplayFromStr")]
     208              :     pub pg_auth_type: AuthType,
     209              :     pub grpc_auth_type: AuthType,
     210              :     pub auth_validation_public_key_path: Option<Utf8PathBuf>,
     211              :     pub remote_storage: Option<RemoteStorageConfig>,
     212              :     pub tenant_config: TenantConfigToml,
     213              :     #[serde_as(as = "serde_with::DisplayFromStr")]
     214              :     pub broker_endpoint: storage_broker::Uri,
     215              :     #[serde(with = "humantime_serde")]
     216              :     pub broker_keepalive_interval: Duration,
     217              :     #[serde_as(as = "serde_with::DisplayFromStr")]
     218              :     pub log_format: LogFormat,
     219              :     pub concurrent_tenant_warmup: NonZeroUsize,
     220              :     pub concurrent_tenant_size_logical_size_queries: NonZeroUsize,
     221              :     #[serde(with = "humantime_serde")]
     222              :     pub metric_collection_interval: Duration,
     223              :     pub metric_collection_endpoint: Option<reqwest::Url>,
     224              :     pub metric_collection_bucket: Option<RemoteStorageConfig>,
     225              :     #[serde(with = "humantime_serde")]
     226              :     pub synthetic_size_calculation_interval: Duration,
     227              :     pub disk_usage_based_eviction: DiskUsageEvictionTaskConfig,
     228              :     pub test_remote_failures: u64,
     229              :     pub test_remote_failures_probability: u64,
     230              :     pub ondemand_download_behavior_treat_error_as_warn: bool,
     231              :     #[serde(with = "humantime_serde")]
     232              :     pub background_task_maximum_delay: Duration,
     233              :     pub control_plane_api: Option<reqwest::Url>,
     234              :     pub control_plane_api_token: Option<String>,
     235              :     pub control_plane_emergency_mode: bool,
     236              :     /// Unstable feature: subject to change or removal without notice.
     237              :     /// See <https://github.com/neondatabase/neon/pull/9218>.
     238              :     pub import_pgdata_upcall_api: Option<reqwest::Url>,
     239              :     /// Unstable feature: subject to change or removal without notice.
     240              :     /// See <https://github.com/neondatabase/neon/pull/9218>.
     241              :     pub import_pgdata_upcall_api_token: Option<String>,
     242              :     /// Unstable feature: subject to change or removal without notice.
     243              :     /// See <https://github.com/neondatabase/neon/pull/9218>.
     244              :     pub import_pgdata_aws_endpoint_url: Option<reqwest::Url>,
     245              :     pub heatmap_upload_concurrency: usize,
     246              :     pub secondary_download_concurrency: usize,
     247              :     pub virtual_file_io_engine: Option<crate::models::virtual_file::IoEngineKind>,
     248              :     pub ingest_batch_size: u64,
     249              :     pub max_vectored_read_bytes: MaxVectoredReadBytes,
     250              :     pub max_get_vectored_keys: MaxGetVectoredKeys,
     251              :     pub image_compression: ImageCompressionAlgorithm,
     252              :     pub timeline_offloading: bool,
     253              :     pub ephemeral_bytes_per_memory_kb: usize,
     254              :     pub l0_flush: Option<crate::models::L0FlushConfig>,
     255              :     pub virtual_file_io_mode: Option<crate::models::virtual_file::IoMode>,
     256              :     #[serde(skip_serializing_if = "Option::is_none")]
     257              :     pub no_sync: Option<bool>,
     258              :     pub page_service_pipelining: PageServicePipeliningConfig,
     259              :     pub get_vectored_concurrent_io: GetVectoredConcurrentIo,
     260              :     pub enable_read_path_debugging: Option<bool>,
     261              :     #[serde(skip_serializing_if = "Option::is_none")]
     262              :     pub validate_wal_contiguity: Option<bool>,
     263              :     #[serde(skip_serializing_if = "Option::is_none")]
     264              :     pub load_previous_heatmap: Option<bool>,
     265              :     #[serde(skip_serializing_if = "Option::is_none")]
     266              :     pub generate_unarchival_heatmap: Option<bool>,
     267              :     pub tracing: Option<Tracing>,
     268              :     pub enable_tls_page_service_api: bool,
     269              :     pub dev_mode: bool,
     270              :     #[serde(skip_serializing_if = "Option::is_none")]
     271              :     pub posthog_config: Option<PostHogConfig>,
     272              :     pub timeline_import_config: TimelineImportConfig,
     273              :     #[serde(skip_serializing_if = "Option::is_none")]
     274              :     pub basebackup_cache_config: Option<BasebackupCacheConfig>,
     275              :     #[serde(skip_serializing_if = "Option::is_none")]
     276              :     pub image_layer_generation_large_timeline_threshold: Option<u64>,
     277              :     pub force_metric_collection_on_scrape: bool,
     278              : }
     279              : 
     280              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     281              : #[serde(default)]
     282              : pub struct DiskUsageEvictionTaskConfig {
     283              :     pub max_usage_pct: utils::serde_percent::Percent,
     284              :     pub min_avail_bytes: u64,
     285              :     #[serde(with = "humantime_serde")]
     286              :     pub period: Duration,
     287              :     #[cfg(feature = "testing")]
     288              :     pub mock_statvfs: Option<statvfs::mock::Behavior>,
     289              :     /// Select sorting for evicted layers
     290              :     #[serde(default)]
     291              :     pub eviction_order: EvictionOrder,
     292              :     pub enabled: bool,
     293              : }
     294              : 
     295              : impl Default for DiskUsageEvictionTaskConfig {
     296          140 :     fn default() -> Self {
     297          140 :         Self {
     298          140 :             max_usage_pct: Percent::new(80).unwrap(),
     299          140 :             min_avail_bytes: 2_000_000_000,
     300          140 :             period: Duration::from_secs(60),
     301          140 :             #[cfg(feature = "testing")]
     302          140 :             mock_statvfs: None,
     303          140 :             eviction_order: EvictionOrder::default(),
     304          140 :             enabled: true,
     305          140 :         }
     306          140 :     }
     307              : }
     308              : 
     309              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     310              : #[serde(tag = "mode", rename_all = "kebab-case")]
     311              : pub enum PageServicePipeliningConfig {
     312              :     Serial,
     313              :     Pipelined(PageServicePipeliningConfigPipelined),
     314              : }
     315            0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     316              : pub struct PageServicePipeliningConfigPipelined {
     317              :     /// Failed config parsing and validation if larger than `max_get_vectored_keys`.
     318              :     pub max_batch_size: NonZeroUsize,
     319              :     pub execution: PageServiceProtocolPipelinedExecutionStrategy,
     320              :     // The default below is such that new versions of the software can start
     321              :     // with the old configuration.
     322              :     #[serde(default)]
     323              :     pub batching: PageServiceProtocolPipelinedBatchingStrategy,
     324              : }
     325              : 
     326            0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     327              : #[serde(rename_all = "kebab-case")]
     328              : pub enum PageServiceProtocolPipelinedExecutionStrategy {
     329              :     ConcurrentFutures,
     330              :     Tasks,
     331              : }
     332              : 
     333            0 : #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     334              : #[serde(rename_all = "kebab-case")]
     335              : pub enum PageServiceProtocolPipelinedBatchingStrategy {
     336              :     /// All get page requests in a batch will be at the same LSN
     337              :     #[default]
     338              :     UniformLsn,
     339              :     /// Get page requests in a batch may be at different LSN
     340              :     ///
     341              :     /// One key cannot be present more than once at different LSNs in
     342              :     /// the same batch.
     343              :     ScatteredLsn,
     344              : }
     345              : 
     346              : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     347              : #[serde(tag = "mode", rename_all = "kebab-case")]
     348              : pub enum GetVectoredConcurrentIo {
     349              :     /// The read path is fully sequential: layers are visited
     350              :     /// one after the other and IOs are issued and waited upon
     351              :     /// from the same task that traverses the layers.
     352              :     Sequential,
     353              :     /// The read path still traverses layers sequentially, and
     354              :     /// index blocks will be read into the PS PageCache from
     355              :     /// that task, with waiting.
     356              :     /// But data IOs are dispatched and waited upon from a sidecar
     357              :     /// task so that the traversing task can continue to traverse
     358              :     /// layers while the IOs are in flight.
     359              :     /// If the PS PageCache miss rate is low, this improves
     360              :     /// throughput dramatically.
     361              :     SidecarTask,
     362              : }
     363              : 
     364            0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     365              : pub struct Ratio {
     366              :     pub numerator: usize,
     367              :     pub denominator: usize,
     368              : }
     369              : 
     370              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     371              : pub struct OtelExporterConfig {
     372              :     pub endpoint: String,
     373              :     pub protocol: OtelExporterProtocol,
     374              :     #[serde(with = "humantime_serde")]
     375              :     pub timeout: Duration,
     376              : }
     377              : 
     378            0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     379              : #[serde(rename_all = "kebab-case")]
     380              : pub enum OtelExporterProtocol {
     381              :     Grpc,
     382              :     HttpBinary,
     383              :     HttpJson,
     384              : }
     385              : 
     386            0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     387              : pub struct Tracing {
     388              :     pub sampling_ratio: Ratio,
     389              :     pub export_config: OtelExporterConfig,
     390              : }
     391              : 
     392              : impl From<&OtelExporterConfig> for tracing_utils::ExportConfig {
     393            0 :     fn from(val: &OtelExporterConfig) -> Self {
     394            0 :         tracing_utils::ExportConfig {
     395            0 :             endpoint: Some(val.endpoint.clone()),
     396            0 :             protocol: val.protocol.into(),
     397            0 :             timeout: val.timeout,
     398            0 :         }
     399            0 :     }
     400              : }
     401              : 
     402              : impl From<OtelExporterProtocol> for tracing_utils::Protocol {
     403            0 :     fn from(val: OtelExporterProtocol) -> Self {
     404            0 :         match val {
     405            0 :             OtelExporterProtocol::Grpc => tracing_utils::Protocol::Grpc,
     406            0 :             OtelExporterProtocol::HttpJson => tracing_utils::Protocol::HttpJson,
     407            0 :             OtelExporterProtocol::HttpBinary => tracing_utils::Protocol::HttpBinary,
     408              :         }
     409            0 :     }
     410              : }
     411              : 
     412            0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     413              : pub struct TimelineImportConfig {
     414              :     pub import_job_concurrency: NonZeroUsize,
     415              :     pub import_job_soft_size_limit: NonZeroUsize,
     416              :     pub import_job_checkpoint_threshold: NonZeroUsize,
     417              :     /// Max size of the remote storage partial read done by any job
     418              :     pub import_job_max_byte_range_size: NonZeroUsize,
     419              : }
     420              : 
     421              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     422              : #[serde(default)]
     423              : pub struct BasebackupCacheConfig {
     424              :     #[serde(with = "humantime_serde")]
     425              :     pub cleanup_period: Duration,
     426              :     /// Maximum total size of basebackup cache entries on disk in bytes.
     427              :     /// The cache may slightly exceed this limit because we do not know
     428              :     /// the exact size of the cache entry untill it's written to disk.
     429              :     pub max_total_size_bytes: u64,
     430              :     // TODO(diko): support max_entry_size_bytes.
     431              :     // pub max_entry_size_bytes: u64,
     432              :     pub max_size_entries: usize,
     433              :     /// Size of the channel used to send prepare requests to the basebackup cache worker.
     434              :     /// If exceeded, new prepare requests will be dropped.
     435              :     pub prepare_channel_size: usize,
     436              : }
     437              : 
     438              : impl Default for BasebackupCacheConfig {
     439            0 :     fn default() -> Self {
     440            0 :         Self {
     441            0 :             cleanup_period: Duration::from_secs(60),
     442            0 :             max_total_size_bytes: 1024 * 1024 * 1024, // 1 GiB
     443            0 :             // max_entry_size_bytes: 16 * 1024 * 1024,   // 16 MiB
     444            0 :             max_size_entries: 10000,
     445            0 :             prepare_channel_size: 100,
     446            0 :         }
     447            0 :     }
     448              : }
     449              : 
     450              : pub mod statvfs {
     451              :     pub mod mock {
     452            0 :         #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     453              :         #[serde(tag = "type")]
     454              :         pub enum Behavior {
     455              :             Success {
     456              :                 blocksize: u64,
     457              :                 total_blocks: u64,
     458              :                 name_filter: Option<utils::serde_regex::Regex>,
     459              :             },
     460              :             #[cfg(feature = "testing")]
     461              :             Failure { mocked_error: MockedError },
     462              :         }
     463              : 
     464              :         #[cfg(feature = "testing")]
     465            0 :         #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     466              :         #[allow(clippy::upper_case_acronyms)]
     467              :         pub enum MockedError {
     468              :             EIO,
     469              :         }
     470              : 
     471              :         #[cfg(feature = "testing")]
     472              :         impl From<MockedError> for nix::Error {
     473            0 :             fn from(e: MockedError) -> Self {
     474            0 :                 match e {
     475            0 :                     MockedError::EIO => nix::Error::EIO,
     476              :                 }
     477            0 :             }
     478              :         }
     479              :     }
     480              : }
     481              : 
     482            0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     483              : #[serde(tag = "type", content = "args")]
     484              : pub enum EvictionOrder {
     485              :     RelativeAccessed {
     486              :         highest_layer_count_loses_first: bool,
     487              :     },
     488              : }
     489              : 
     490              : impl Default for EvictionOrder {
     491          144 :     fn default() -> Self {
     492          144 :         Self::RelativeAccessed {
     493          144 :             highest_layer_count_loses_first: true,
     494          144 :         }
     495          144 :     }
     496              : }
     497              : 
     498              : #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     499              : #[serde(transparent)]
     500              : pub struct MaxVectoredReadBytes(pub NonZeroUsize);
     501              : 
     502              : #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     503              : #[serde(transparent)]
     504              : pub struct MaxGetVectoredKeys(NonZeroUsize);
     505              : 
     506              : impl MaxGetVectoredKeys {
     507        72004 :     pub fn get(&self) -> usize {
     508        72004 :         self.0.get()
     509        72004 :     }
     510              : }
     511              : 
     512              : /// Tenant-level configuration values, used for various purposes.
     513              : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
     514              : #[serde(default)]
     515              : pub struct TenantConfigToml {
     516              :     // Flush out an inmemory layer, if it's holding WAL older than this
     517              :     // This puts a backstop on how much WAL needs to be re-digested if the
     518              :     // page server crashes.
     519              :     // This parameter actually determines L0 layer file size.
     520              :     pub checkpoint_distance: u64,
     521              :     // Inmemory layer is also flushed at least once in checkpoint_timeout to
     522              :     // eventually upload WAL after activity is stopped.
     523              :     #[serde(with = "humantime_serde")]
     524              :     pub checkpoint_timeout: Duration,
     525              :     // Target file size, when creating image and delta layers.
     526              :     // This parameter determines L1 layer file size.
     527              :     pub compaction_target_size: u64,
     528              :     // How often to check if there's compaction work to be done.
     529              :     // Duration::ZERO means automatic compaction is disabled.
     530              :     #[serde(with = "humantime_serde")]
     531              :     pub compaction_period: Duration,
     532              :     /// Level0 delta layer threshold for compaction.
     533              :     pub compaction_threshold: usize,
     534              :     /// Controls the amount of L0 included in a single compaction iteration.
     535              :     /// The unit is `checkpoint_distance`, i.e., a size.
     536              :     /// We add L0s to the set of layers to compact until their cumulative
     537              :     /// size exceeds `compaction_upper_limit * checkpoint_distance`.
     538              :     pub compaction_upper_limit: usize,
     539              :     pub compaction_algorithm: crate::models::CompactionAlgorithmSettings,
     540              :     /// If true, enable shard ancestor compaction (enabled by default).
     541              :     pub compaction_shard_ancestor: bool,
     542              :     /// If true, compact down L0 across all tenant timelines before doing regular compaction. L0
     543              :     /// compaction must be responsive to avoid read amp during heavy ingestion. Defaults to true.
     544              :     pub compaction_l0_first: bool,
     545              :     /// If true, use a separate semaphore (i.e. concurrency limit) for the L0 compaction pass. Only
     546              :     /// has an effect if `compaction_l0_first` is true. Defaults to true.
     547              :     pub compaction_l0_semaphore: bool,
     548              :     /// Level0 delta layer threshold at which to delay layer flushes such that they take 2x as long,
     549              :     /// and block on layer flushes during ephemeral layer rolls, for compaction backpressure. This
     550              :     /// helps compaction keep up with WAL ingestion, and avoids read amplification blowing up.
     551              :     /// Should be >compaction_threshold. 0 to disable. Defaults to 3x compaction_threshold.
     552              :     pub l0_flush_delay_threshold: Option<usize>,
     553              :     /// Level0 delta layer threshold at which to stall layer flushes. Must be >compaction_threshold
     554              :     /// to avoid deadlock. 0 to disable. Disabled by default.
     555              :     pub l0_flush_stall_threshold: Option<usize>,
     556              :     // Determines how much history is retained, to allow
     557              :     // branching and read replicas at an older point in time.
     558              :     // The unit is #of bytes of WAL.
     559              :     // Page versions older than this are garbage collected away.
     560              :     pub gc_horizon: u64,
     561              :     // Interval at which garbage collection is triggered.
     562              :     // Duration::ZERO means automatic GC is disabled
     563              :     #[serde(with = "humantime_serde")]
     564              :     pub gc_period: Duration,
     565              :     // Delta layer churn threshold to create L1 image layers.
     566              :     pub image_creation_threshold: usize,
     567              :     // HADRON
     568              :     // When the timeout is reached, PageServer will (1) force compact any remaining L0 deltas and
     569              :     // (2) create image layers if there are any L1 deltas.
     570              :     #[serde(with = "humantime_serde")]
     571              :     pub image_layer_force_creation_period: Option<Duration>,
     572              :     // Determines how much history is retained, to allow
     573              :     // branching and read replicas at an older point in time.
     574              :     // The unit is time.
     575              :     // Page versions older than this are garbage collected away.
     576              :     #[serde(with = "humantime_serde")]
     577              :     pub pitr_interval: Duration,
     578              :     /// Maximum amount of time to wait while opening a connection to receive wal, before erroring.
     579              :     #[serde(with = "humantime_serde")]
     580              :     pub walreceiver_connect_timeout: Duration,
     581              :     /// Considers safekeepers stalled after no WAL updates were received longer than this threshold.
     582              :     /// A stalled safekeeper will be changed to a newer one when it appears.
     583              :     #[serde(with = "humantime_serde")]
     584              :     pub lagging_wal_timeout: Duration,
     585              :     /// Considers safekeepers lagging when their WAL is behind another safekeeper for more than this threshold.
     586              :     /// A lagging safekeeper will be changed after `lagging_wal_timeout` time elapses since the last WAL update,
     587              :     /// to avoid eager reconnects.
     588              :     pub max_lsn_wal_lag: NonZeroU64,
     589              :     pub eviction_policy: crate::models::EvictionPolicy,
     590              :     pub min_resident_size_override: Option<u64>,
     591              :     // See the corresponding metric's help string.
     592              :     #[serde(with = "humantime_serde")]
     593              :     pub evictions_low_residence_duration_metric_threshold: Duration,
     594              : 
     595              :     /// If non-zero, the period between uploads of a heatmap from attached tenants.  This
     596              :     /// may be disabled if a Tenant will not have secondary locations: only secondary
     597              :     /// locations will use the heatmap uploaded by attached locations.
     598              :     #[serde(with = "humantime_serde")]
     599              :     pub heatmap_period: Duration,
     600              : 
     601              :     /// If true then SLRU segments are dowloaded on demand, if false SLRU segments are included in basebackup
     602              :     pub lazy_slru_download: bool,
     603              : 
     604              :     pub timeline_get_throttle: crate::models::ThrottleConfig,
     605              : 
     606              :     // How much WAL must be ingested before checking again whether a new image layer is required.
     607              :     // Expresed in multiples of checkpoint distance.
     608              :     pub image_layer_creation_check_threshold: u8,
     609              : 
     610              :     // How many multiples of L0 `compaction_threshold` will preempt image layer creation and do L0 compaction.
     611              :     // Set to 0 to disable preemption.
     612              :     pub image_creation_preempt_threshold: usize,
     613              : 
     614              :     /// The length for an explicit LSN lease request.
     615              :     /// Layers needed to reconstruct pages at LSN will not be GC-ed during this interval.
     616              :     #[serde(with = "humantime_serde")]
     617              :     pub lsn_lease_length: Duration,
     618              : 
     619              :     /// The length for an implicit LSN lease granted as part of `get_lsn_by_timestamp` request.
     620              :     /// Layers needed to reconstruct pages at LSN will not be GC-ed during this interval.
     621              :     #[serde(with = "humantime_serde")]
     622              :     pub lsn_lease_length_for_ts: Duration,
     623              : 
     624              :     /// Enable auto-offloading of timelines.
     625              :     /// (either this flag or the pageserver-global one need to be set)
     626              :     pub timeline_offloading: bool,
     627              : 
     628              :     /// Enable rel_size_v2 for this tenant. Once enabled, the tenant will persist this information into
     629              :     /// `index_part.json`, and it cannot be reversed.
     630              :     pub rel_size_v2_enabled: bool,
     631              : 
     632              :     // gc-compaction related configs
     633              :     /// Enable automatic gc-compaction trigger on this tenant.
     634              :     pub gc_compaction_enabled: bool,
     635              :     /// Enable verification of gc-compaction results.
     636              :     pub gc_compaction_verification: bool,
     637              :     /// The initial threshold for gc-compaction in KB. Once the total size of layers below the gc-horizon is above this threshold,
     638              :     /// gc-compaction will be triggered.
     639              :     pub gc_compaction_initial_threshold_kb: u64,
     640              :     /// The ratio that triggers the auto gc-compaction. If (the total size of layers between L2 LSN and gc-horizon) / (size below the L2 LSN)
     641              :     /// is above this ratio, gc-compaction will be triggered.
     642              :     pub gc_compaction_ratio_percent: u64,
     643              :     /// Tenant level performance sampling ratio override. Controls the ratio of get page requests
     644              :     /// that will get perf sampling for the tenant.
     645              :     pub sampling_ratio: Option<Ratio>,
     646              : 
     647              :     /// Capacity of relsize snapshot cache (used by replicas).
     648              :     pub relsize_snapshot_cache_capacity: usize,
     649              : 
     650              :     /// Enable preparing basebackup on XLOG_CHECKPOINT_SHUTDOWN and using it in basebackup requests.
     651              :     // FIXME: Remove skip_serializing_if when the feature is stable.
     652              :     #[serde(skip_serializing_if = "std::ops::Not::not")]
     653              :     pub basebackup_cache_enabled: bool,
     654              : }
     655              : 
     656              : pub mod defaults {
     657              :     pub use storage_broker::DEFAULT_ENDPOINT as BROKER_DEFAULT_ENDPOINT;
     658              : 
     659              :     use crate::models::ImageCompressionAlgorithm;
     660              : 
     661              :     pub const DEFAULT_WAIT_LSN_TIMEOUT: &str = "300 s";
     662              :     pub const DEFAULT_WAL_REDO_TIMEOUT: &str = "60 s";
     663              : 
     664              :     pub const DEFAULT_SUPERUSER: &str = "cloud_admin";
     665              :     pub const DEFAULT_LOCALE: &str = if cfg!(target_os = "macos") {
     666              :         "C"
     667              :     } else {
     668              :         "C.UTF-8"
     669              :     };
     670              : 
     671              :     pub const DEFAULT_PAGE_CACHE_SIZE: usize = 8192;
     672              :     pub const DEFAULT_MAX_FILE_DESCRIPTORS: usize = 100;
     673              : 
     674              :     pub const DEFAULT_LOG_FORMAT: &str = "plain";
     675              : 
     676              :     pub const DEFAULT_CONCURRENT_TENANT_WARMUP: usize = 8;
     677              : 
     678              :     pub const DEFAULT_CONCURRENT_TENANT_SIZE_LOGICAL_SIZE_QUERIES: usize = 1;
     679              : 
     680              :     pub const DEFAULT_METRIC_COLLECTION_INTERVAL: &str = "10 min";
     681              :     pub const DEFAULT_METRIC_COLLECTION_ENDPOINT: Option<reqwest::Url> = None;
     682              :     pub const DEFAULT_SYNTHETIC_SIZE_CALCULATION_INTERVAL: &str = "10 min";
     683              :     pub const DEFAULT_BACKGROUND_TASK_MAXIMUM_DELAY: &str = "10s";
     684              : 
     685              :     pub const DEFAULT_HEATMAP_UPLOAD_CONCURRENCY: usize = 8;
     686              :     pub const DEFAULT_SECONDARY_DOWNLOAD_CONCURRENCY: usize = 1;
     687              : 
     688              :     pub const DEFAULT_INGEST_BATCH_SIZE: u64 = 100;
     689              : 
     690              :     /// Soft limit for the maximum size of a vectored read.
     691              :     ///
     692              :     /// This is determined by the largest NeonWalRecord that can exist (minus dbdir and reldir keys
     693              :     /// which are bounded by the blob io limits only). As of this writing, that is a `NeonWalRecord::ClogSetCommitted` record,
     694              :     /// with 32k xids. That's the max number of XIDS on a single CLOG page. The size of such a record
     695              :     /// is `sizeof(Transactionid) * 32768 + (some fixed overhead from 'timestamp`, the Vec length and whatever extra serde serialization adds)`.
     696              :     /// That is, slightly above 128 kB.
     697              :     pub const DEFAULT_MAX_VECTORED_READ_BYTES: usize = 130 * 1024; // 130 KiB
     698              : 
     699              :     pub const DEFAULT_MAX_GET_VECTORED_KEYS: usize = 32;
     700              : 
     701              :     pub const DEFAULT_IMAGE_COMPRESSION: ImageCompressionAlgorithm =
     702              :         ImageCompressionAlgorithm::Zstd { level: Some(1) };
     703              : 
     704              :     pub const DEFAULT_EPHEMERAL_BYTES_PER_MEMORY_KB: usize = 0;
     705              : 
     706              :     pub const DEFAULT_IO_BUFFER_ALIGNMENT: usize = 512;
     707              : 
     708              :     pub const DEFAULT_SSL_KEY_FILE: &str = "server.key";
     709              :     pub const DEFAULT_SSL_CERT_FILE: &str = "server.crt";
     710              : }
     711              : 
     712              : impl Default for ConfigToml {
     713          138 :     fn default() -> Self {
     714              :         use defaults::*;
     715              : 
     716              :         Self {
     717          138 :             listen_pg_addr: (DEFAULT_PG_LISTEN_ADDR.to_string()),
     718          138 :             listen_http_addr: (DEFAULT_HTTP_LISTEN_ADDR.to_string()),
     719          138 :             listen_https_addr: (None),
     720          138 :             listen_grpc_addr: None, // TODO: default to 127.0.0.1:51051
     721          138 :             ssl_key_file: Utf8PathBuf::from(DEFAULT_SSL_KEY_FILE),
     722          138 :             ssl_cert_file: Utf8PathBuf::from(DEFAULT_SSL_CERT_FILE),
     723          138 :             ssl_cert_reload_period: Duration::from_secs(60),
     724          138 :             ssl_ca_file: None,
     725          138 :             availability_zone: (None),
     726          138 :             wait_lsn_timeout: (humantime::parse_duration(DEFAULT_WAIT_LSN_TIMEOUT)
     727          138 :                 .expect("cannot parse default wait lsn timeout")),
     728          138 :             wal_redo_timeout: (humantime::parse_duration(DEFAULT_WAL_REDO_TIMEOUT)
     729          138 :                 .expect("cannot parse default wal redo timeout")),
     730          138 :             superuser: (DEFAULT_SUPERUSER.to_string()),
     731          138 :             locale: DEFAULT_LOCALE.to_string(),
     732              :             page_cache_size: (DEFAULT_PAGE_CACHE_SIZE),
     733              :             max_file_descriptors: (DEFAULT_MAX_FILE_DESCRIPTORS),
     734          138 :             pg_distrib_dir: None, // Utf8PathBuf::from("./pg_install"), // TODO: formely, this was std::env::current_dir()
     735          138 :             http_auth_type: (AuthType::Trust),
     736          138 :             pg_auth_type: (AuthType::Trust),
     737          138 :             grpc_auth_type: (AuthType::Trust),
     738          138 :             auth_validation_public_key_path: (None),
     739          138 :             remote_storage: None,
     740          138 :             broker_endpoint: (storage_broker::DEFAULT_ENDPOINT
     741          138 :                 .parse()
     742          138 :                 .expect("failed to parse default broker endpoint")),
     743          138 :             broker_keepalive_interval: (humantime::parse_duration(
     744          138 :                 storage_broker::DEFAULT_KEEPALIVE_INTERVAL,
     745              :             )
     746          138 :             .expect("cannot parse default keepalive interval")),
     747          138 :             log_format: (LogFormat::from_str(DEFAULT_LOG_FORMAT).unwrap()),
     748              : 
     749          138 :             concurrent_tenant_warmup: (NonZeroUsize::new(DEFAULT_CONCURRENT_TENANT_WARMUP)
     750          138 :                 .expect("Invalid default constant")),
     751          138 :             concurrent_tenant_size_logical_size_queries: NonZeroUsize::new(
     752              :                 DEFAULT_CONCURRENT_TENANT_SIZE_LOGICAL_SIZE_QUERIES,
     753              :             )
     754          138 :             .unwrap(),
     755          138 :             metric_collection_interval: (humantime::parse_duration(
     756          138 :                 DEFAULT_METRIC_COLLECTION_INTERVAL,
     757              :             )
     758          138 :             .expect("cannot parse default metric collection interval")),
     759          138 :             synthetic_size_calculation_interval: (humantime::parse_duration(
     760          138 :                 DEFAULT_SYNTHETIC_SIZE_CALCULATION_INTERVAL,
     761              :             )
     762          138 :             .expect("cannot parse default synthetic size calculation interval")),
     763          138 :             metric_collection_endpoint: (DEFAULT_METRIC_COLLECTION_ENDPOINT),
     764              : 
     765          138 :             metric_collection_bucket: (None),
     766              : 
     767          138 :             disk_usage_based_eviction: DiskUsageEvictionTaskConfig::default(),
     768              : 
     769              :             test_remote_failures: (0),
     770              :             test_remote_failures_probability: (100),
     771              : 
     772              :             ondemand_download_behavior_treat_error_as_warn: (false),
     773              : 
     774          138 :             background_task_maximum_delay: (humantime::parse_duration(
     775          138 :                 DEFAULT_BACKGROUND_TASK_MAXIMUM_DELAY,
     776              :             )
     777          138 :             .unwrap()),
     778              : 
     779          138 :             control_plane_api: (None),
     780          138 :             control_plane_api_token: (None),
     781              :             control_plane_emergency_mode: (false),
     782              : 
     783          138 :             import_pgdata_upcall_api: (None),
     784          138 :             import_pgdata_upcall_api_token: (None),
     785          138 :             import_pgdata_aws_endpoint_url: (None),
     786              : 
     787              :             heatmap_upload_concurrency: (DEFAULT_HEATMAP_UPLOAD_CONCURRENCY),
     788              :             secondary_download_concurrency: (DEFAULT_SECONDARY_DOWNLOAD_CONCURRENCY),
     789              : 
     790              :             ingest_batch_size: (DEFAULT_INGEST_BATCH_SIZE),
     791              : 
     792          138 :             virtual_file_io_engine: None,
     793              : 
     794          138 :             max_vectored_read_bytes: (MaxVectoredReadBytes(
     795          138 :                 NonZeroUsize::new(DEFAULT_MAX_VECTORED_READ_BYTES).unwrap(),
     796          138 :             )),
     797          138 :             max_get_vectored_keys: (MaxGetVectoredKeys(
     798          138 :                 NonZeroUsize::new(DEFAULT_MAX_GET_VECTORED_KEYS).unwrap(),
     799          138 :             )),
     800              :             image_compression: (DEFAULT_IMAGE_COMPRESSION),
     801              :             timeline_offloading: true,
     802              :             ephemeral_bytes_per_memory_kb: (DEFAULT_EPHEMERAL_BYTES_PER_MEMORY_KB),
     803          138 :             l0_flush: None,
     804          138 :             virtual_file_io_mode: None,
     805          138 :             tenant_config: TenantConfigToml::default(),
     806          138 :             no_sync: None,
     807          138 :             page_service_pipelining: PageServicePipeliningConfig::Pipelined(
     808          138 :                 PageServicePipeliningConfigPipelined {
     809          138 :                     max_batch_size: NonZeroUsize::new(32).unwrap(),
     810          138 :                     execution: PageServiceProtocolPipelinedExecutionStrategy::ConcurrentFutures,
     811          138 :                     batching: PageServiceProtocolPipelinedBatchingStrategy::ScatteredLsn,
     812          138 :                 },
     813          138 :             ),
     814          138 :             get_vectored_concurrent_io: GetVectoredConcurrentIo::SidecarTask,
     815          138 :             enable_read_path_debugging: if cfg!(feature = "testing") {
     816          138 :                 Some(true)
     817              :             } else {
     818            0 :                 None
     819              :             },
     820          138 :             validate_wal_contiguity: None,
     821          138 :             load_previous_heatmap: None,
     822          138 :             generate_unarchival_heatmap: None,
     823          138 :             tracing: None,
     824              :             enable_tls_page_service_api: false,
     825              :             dev_mode: false,
     826          138 :             timeline_import_config: TimelineImportConfig {
     827          138 :                 import_job_concurrency: NonZeroUsize::new(32).unwrap(),
     828          138 :                 import_job_soft_size_limit: NonZeroUsize::new(256 * 1024 * 1024).unwrap(),
     829          138 :                 import_job_checkpoint_threshold: NonZeroUsize::new(32).unwrap(),
     830          138 :                 import_job_max_byte_range_size: NonZeroUsize::new(4 * 1024 * 1024).unwrap(),
     831          138 :             },
     832          138 :             basebackup_cache_config: None,
     833          138 :             posthog_config: None,
     834          138 :             image_layer_generation_large_timeline_threshold: Some(2 * 1024 * 1024 * 1024),
     835              :             force_metric_collection_on_scrape: true,
     836              :         }
     837          138 :     }
     838              : }
     839              : 
     840              : pub mod tenant_conf_defaults {
     841              : 
     842              :     // FIXME: This current value is very low. I would imagine something like 1 GB or 10 GB
     843              :     // would be more appropriate. But a low value forces the code to be exercised more,
     844              :     // which is good for now to trigger bugs.
     845              :     // This parameter actually determines L0 layer file size.
     846              :     pub const DEFAULT_CHECKPOINT_DISTANCE: u64 = 256 * 1024 * 1024;
     847              :     pub const DEFAULT_CHECKPOINT_TIMEOUT: &str = "10 m";
     848              : 
     849              :     // FIXME the below configs are only used by legacy algorithm. The new algorithm
     850              :     // has different parameters.
     851              : 
     852              :     // Target file size, when creating image and delta layers.
     853              :     // This parameter determines L1 layer file size.
     854              :     pub const DEFAULT_COMPACTION_TARGET_SIZE: u64 = 128 * 1024 * 1024;
     855              : 
     856              :     pub const DEFAULT_COMPACTION_PERIOD: &str = "20 s";
     857              :     pub const DEFAULT_COMPACTION_THRESHOLD: usize = 10;
     858              :     pub const DEFAULT_COMPACTION_SHARD_ANCESTOR: bool = true;
     859              : 
     860              :     // This value needs to be tuned to avoid OOM. We have 3/4*CPUs threads for L0 compaction, that's
     861              :     // 3/4*8=6 on most of our pageservers. Compacting 10 layers requires a maximum of
     862              :     // DEFAULT_CHECKPOINT_DISTANCE*10 memory, that's 2560MB. So with this config, we can get a maximum peak
     863              :     // compaction usage of 15360MB.
     864              :     pub const DEFAULT_COMPACTION_UPPER_LIMIT: usize = 10;
     865              :     // Enable L0 compaction pass and semaphore by default. L0 compaction must be responsive to avoid
     866              :     // read amp.
     867              :     pub const DEFAULT_COMPACTION_L0_FIRST: bool = true;
     868              :     pub const DEFAULT_COMPACTION_L0_SEMAPHORE: bool = true;
     869              : 
     870              :     pub const DEFAULT_COMPACTION_ALGORITHM: crate::models::CompactionAlgorithm =
     871              :         crate::models::CompactionAlgorithm::Legacy;
     872              : 
     873              :     pub const DEFAULT_GC_HORIZON: u64 = 64 * 1024 * 1024;
     874              : 
     875              :     // Large DEFAULT_GC_PERIOD is fine as long as PITR_INTERVAL is larger.
     876              :     // If there's a need to decrease this value, first make sure that GC
     877              :     // doesn't hold a layer map write lock for non-trivial operations.
     878              :     // Relevant: https://github.com/neondatabase/neon/issues/3394
     879              :     pub const DEFAULT_GC_PERIOD: &str = "1 hr";
     880              :     pub const DEFAULT_IMAGE_CREATION_THRESHOLD: usize = 3;
     881              :     // Currently, any value other than 0 will trigger image layer creation preemption immediately with L0 backpressure
     882              :     // without looking at the exact number of L0 layers.
     883              :     // It was expected to have the following behavior:
     884              :     // > If there are more than threshold * compaction_threshold (that is 3 * 10 in the default config) L0 layers, image
     885              :     // > layer creation will end immediately. Set to 0 to disable.
     886              :     pub const DEFAULT_IMAGE_CREATION_PREEMPT_THRESHOLD: usize = 3;
     887              :     pub const DEFAULT_PITR_INTERVAL: &str = "7 days";
     888              :     pub const DEFAULT_WALRECEIVER_CONNECT_TIMEOUT: &str = "10 seconds";
     889              :     pub const DEFAULT_WALRECEIVER_LAGGING_WAL_TIMEOUT: &str = "10 seconds";
     890              :     // The default limit on WAL lag should be set to avoid causing disconnects under high throughput
     891              :     // scenarios: since the broker stats are updated ~1/s, a value of 1GiB should be sufficient for
     892              :     // throughputs up to 1GiB/s per timeline.
     893              :     pub const DEFAULT_MAX_WALRECEIVER_LSN_WAL_LAG: u64 = 1024 * 1024 * 1024;
     894              :     pub const DEFAULT_EVICTIONS_LOW_RESIDENCE_DURATION_METRIC_THRESHOLD: &str = "24 hour";
     895              :     // By default ingest enough WAL for two new L0 layers before checking if new image
     896              :     // image layers should be created.
     897              :     pub const DEFAULT_IMAGE_LAYER_CREATION_CHECK_THRESHOLD: u8 = 2;
     898              :     pub const DEFAULT_GC_COMPACTION_ENABLED: bool = true;
     899              :     pub const DEFAULT_GC_COMPACTION_VERIFICATION: bool = true;
     900              :     pub const DEFAULT_GC_COMPACTION_INITIAL_THRESHOLD_KB: u64 = 5 * 1024 * 1024; // 5GB
     901              :     pub const DEFAULT_GC_COMPACTION_RATIO_PERCENT: u64 = 100;
     902              :     pub const DEFAULT_RELSIZE_SNAPSHOT_CACHE_CAPACITY: usize = 1000;
     903              : }
     904              : 
     905              : impl Default for TenantConfigToml {
     906          138 :     fn default() -> Self {
     907              :         use tenant_conf_defaults::*;
     908          138 :         Self {
     909          138 :             checkpoint_distance: DEFAULT_CHECKPOINT_DISTANCE,
     910          138 :             checkpoint_timeout: humantime::parse_duration(DEFAULT_CHECKPOINT_TIMEOUT)
     911          138 :                 .expect("cannot parse default checkpoint timeout"),
     912          138 :             compaction_target_size: DEFAULT_COMPACTION_TARGET_SIZE,
     913          138 :             compaction_period: humantime::parse_duration(DEFAULT_COMPACTION_PERIOD)
     914          138 :                 .expect("cannot parse default compaction period"),
     915          138 :             compaction_threshold: DEFAULT_COMPACTION_THRESHOLD,
     916          138 :             compaction_upper_limit: DEFAULT_COMPACTION_UPPER_LIMIT,
     917          138 :             compaction_algorithm: crate::models::CompactionAlgorithmSettings {
     918          138 :                 kind: DEFAULT_COMPACTION_ALGORITHM,
     919          138 :             },
     920          138 :             compaction_shard_ancestor: DEFAULT_COMPACTION_SHARD_ANCESTOR,
     921          138 :             compaction_l0_first: DEFAULT_COMPACTION_L0_FIRST,
     922          138 :             compaction_l0_semaphore: DEFAULT_COMPACTION_L0_SEMAPHORE,
     923          138 :             l0_flush_delay_threshold: None,
     924          138 :             l0_flush_stall_threshold: None,
     925          138 :             gc_horizon: DEFAULT_GC_HORIZON,
     926          138 :             gc_period: humantime::parse_duration(DEFAULT_GC_PERIOD)
     927          138 :                 .expect("cannot parse default gc period"),
     928          138 :             image_creation_threshold: DEFAULT_IMAGE_CREATION_THRESHOLD,
     929          138 :             image_layer_force_creation_period: None,
     930          138 :             pitr_interval: humantime::parse_duration(DEFAULT_PITR_INTERVAL)
     931          138 :                 .expect("cannot parse default PITR interval"),
     932          138 :             walreceiver_connect_timeout: humantime::parse_duration(
     933          138 :                 DEFAULT_WALRECEIVER_CONNECT_TIMEOUT,
     934          138 :             )
     935          138 :             .expect("cannot parse default walreceiver connect timeout"),
     936          138 :             lagging_wal_timeout: humantime::parse_duration(DEFAULT_WALRECEIVER_LAGGING_WAL_TIMEOUT)
     937          138 :                 .expect("cannot parse default walreceiver lagging wal timeout"),
     938          138 :             max_lsn_wal_lag: NonZeroU64::new(DEFAULT_MAX_WALRECEIVER_LSN_WAL_LAG)
     939          138 :                 .expect("cannot parse default max walreceiver Lsn wal lag"),
     940          138 :             eviction_policy: crate::models::EvictionPolicy::NoEviction,
     941          138 :             min_resident_size_override: None,
     942          138 :             evictions_low_residence_duration_metric_threshold: humantime::parse_duration(
     943          138 :                 DEFAULT_EVICTIONS_LOW_RESIDENCE_DURATION_METRIC_THRESHOLD,
     944          138 :             )
     945          138 :             .expect("cannot parse default evictions_low_residence_duration_metric_threshold"),
     946          138 :             heatmap_period: Duration::ZERO,
     947          138 :             lazy_slru_download: false,
     948          138 :             timeline_get_throttle: crate::models::ThrottleConfig::disabled(),
     949          138 :             image_layer_creation_check_threshold: DEFAULT_IMAGE_LAYER_CREATION_CHECK_THRESHOLD,
     950          138 :             image_creation_preempt_threshold: DEFAULT_IMAGE_CREATION_PREEMPT_THRESHOLD,
     951          138 :             lsn_lease_length: LsnLease::DEFAULT_LENGTH,
     952          138 :             lsn_lease_length_for_ts: LsnLease::DEFAULT_LENGTH_FOR_TS,
     953          138 :             timeline_offloading: true,
     954          138 :             rel_size_v2_enabled: false,
     955          138 :             gc_compaction_enabled: DEFAULT_GC_COMPACTION_ENABLED,
     956          138 :             gc_compaction_verification: DEFAULT_GC_COMPACTION_VERIFICATION,
     957          138 :             gc_compaction_initial_threshold_kb: DEFAULT_GC_COMPACTION_INITIAL_THRESHOLD_KB,
     958          138 :             gc_compaction_ratio_percent: DEFAULT_GC_COMPACTION_RATIO_PERCENT,
     959          138 :             sampling_ratio: None,
     960          138 :             relsize_snapshot_cache_capacity: DEFAULT_RELSIZE_SNAPSHOT_CACHE_CAPACITY,
     961          138 :             basebackup_cache_enabled: false,
     962          138 :         }
     963          138 :     }
     964              : }
        

Generated by: LCOV version 2.1-beta