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 ondemand_download_behavior_treat_error_as_warn: bool,
230 : #[serde(with = "humantime_serde")]
231 : pub background_task_maximum_delay: Duration,
232 : pub control_plane_api: Option<reqwest::Url>,
233 : pub control_plane_api_token: Option<String>,
234 : pub control_plane_emergency_mode: bool,
235 : /// Unstable feature: subject to change or removal without notice.
236 : /// See <https://github.com/neondatabase/neon/pull/9218>.
237 : pub import_pgdata_upcall_api: Option<reqwest::Url>,
238 : /// Unstable feature: subject to change or removal without notice.
239 : /// See <https://github.com/neondatabase/neon/pull/9218>.
240 : pub import_pgdata_upcall_api_token: Option<String>,
241 : /// Unstable feature: subject to change or removal without notice.
242 : /// See <https://github.com/neondatabase/neon/pull/9218>.
243 : pub import_pgdata_aws_endpoint_url: Option<reqwest::Url>,
244 : pub heatmap_upload_concurrency: usize,
245 : pub secondary_download_concurrency: usize,
246 : pub virtual_file_io_engine: Option<crate::models::virtual_file::IoEngineKind>,
247 : pub ingest_batch_size: u64,
248 : pub max_vectored_read_bytes: MaxVectoredReadBytes,
249 : pub max_get_vectored_keys: MaxGetVectoredKeys,
250 : pub image_compression: ImageCompressionAlgorithm,
251 : pub timeline_offloading: bool,
252 : pub ephemeral_bytes_per_memory_kb: usize,
253 : pub l0_flush: Option<crate::models::L0FlushConfig>,
254 : pub virtual_file_io_mode: Option<crate::models::virtual_file::IoMode>,
255 : #[serde(skip_serializing_if = "Option::is_none")]
256 : pub no_sync: Option<bool>,
257 : pub page_service_pipelining: PageServicePipeliningConfig,
258 : pub get_vectored_concurrent_io: GetVectoredConcurrentIo,
259 : pub enable_read_path_debugging: Option<bool>,
260 : #[serde(skip_serializing_if = "Option::is_none")]
261 : pub validate_wal_contiguity: Option<bool>,
262 : #[serde(skip_serializing_if = "Option::is_none")]
263 : pub load_previous_heatmap: Option<bool>,
264 : #[serde(skip_serializing_if = "Option::is_none")]
265 : pub generate_unarchival_heatmap: Option<bool>,
266 : pub tracing: Option<Tracing>,
267 : pub enable_tls_page_service_api: bool,
268 : pub dev_mode: bool,
269 : #[serde(skip_serializing_if = "Option::is_none")]
270 : pub posthog_config: Option<PostHogConfig>,
271 : pub timeline_import_config: TimelineImportConfig,
272 : #[serde(skip_serializing_if = "Option::is_none")]
273 : pub basebackup_cache_config: Option<BasebackupCacheConfig>,
274 : }
275 :
276 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
277 : #[serde(default)]
278 : pub struct DiskUsageEvictionTaskConfig {
279 : pub max_usage_pct: utils::serde_percent::Percent,
280 : pub min_avail_bytes: u64,
281 : #[serde(with = "humantime_serde")]
282 : pub period: Duration,
283 : #[cfg(feature = "testing")]
284 : pub mock_statvfs: Option<statvfs::mock::Behavior>,
285 : /// Select sorting for evicted layers
286 : #[serde(default)]
287 : pub eviction_order: EvictionOrder,
288 : pub enabled: bool,
289 : }
290 :
291 : impl Default for DiskUsageEvictionTaskConfig {
292 139 : fn default() -> Self {
293 139 : Self {
294 139 : max_usage_pct: Percent::new(80).unwrap(),
295 139 : min_avail_bytes: 2_000_000_000,
296 139 : period: Duration::from_secs(60),
297 139 : #[cfg(feature = "testing")]
298 139 : mock_statvfs: None,
299 139 : eviction_order: EvictionOrder::default(),
300 139 : enabled: true,
301 139 : }
302 139 : }
303 : }
304 :
305 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
306 : #[serde(tag = "mode", rename_all = "kebab-case")]
307 : pub enum PageServicePipeliningConfig {
308 : Serial,
309 : Pipelined(PageServicePipeliningConfigPipelined),
310 : }
311 0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
312 : pub struct PageServicePipeliningConfigPipelined {
313 : /// Failed config parsing and validation if larger than `max_get_vectored_keys`.
314 : pub max_batch_size: NonZeroUsize,
315 : pub execution: PageServiceProtocolPipelinedExecutionStrategy,
316 : // The default below is such that new versions of the software can start
317 : // with the old configuration.
318 : #[serde(default)]
319 : pub batching: PageServiceProtocolPipelinedBatchingStrategy,
320 : }
321 :
322 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
323 : #[serde(rename_all = "kebab-case")]
324 : pub enum PageServiceProtocolPipelinedExecutionStrategy {
325 : ConcurrentFutures,
326 : Tasks,
327 : }
328 :
329 0 : #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
330 : #[serde(rename_all = "kebab-case")]
331 : pub enum PageServiceProtocolPipelinedBatchingStrategy {
332 : /// All get page requests in a batch will be at the same LSN
333 : #[default]
334 : UniformLsn,
335 : /// Get page requests in a batch may be at different LSN
336 : ///
337 : /// One key cannot be present more than once at different LSNs in
338 : /// the same batch.
339 : ScatteredLsn,
340 : }
341 :
342 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
343 : #[serde(tag = "mode", rename_all = "kebab-case")]
344 : pub enum GetVectoredConcurrentIo {
345 : /// The read path is fully sequential: layers are visited
346 : /// one after the other and IOs are issued and waited upon
347 : /// from the same task that traverses the layers.
348 : Sequential,
349 : /// The read path still traverses layers sequentially, and
350 : /// index blocks will be read into the PS PageCache from
351 : /// that task, with waiting.
352 : /// But data IOs are dispatched and waited upon from a sidecar
353 : /// task so that the traversing task can continue to traverse
354 : /// layers while the IOs are in flight.
355 : /// If the PS PageCache miss rate is low, this improves
356 : /// throughput dramatically.
357 : SidecarTask,
358 : }
359 :
360 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
361 : pub struct Ratio {
362 : pub numerator: usize,
363 : pub denominator: usize,
364 : }
365 :
366 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
367 : pub struct OtelExporterConfig {
368 : pub endpoint: String,
369 : pub protocol: OtelExporterProtocol,
370 : #[serde(with = "humantime_serde")]
371 : pub timeout: Duration,
372 : }
373 :
374 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
375 : #[serde(rename_all = "kebab-case")]
376 : pub enum OtelExporterProtocol {
377 : Grpc,
378 : HttpBinary,
379 : HttpJson,
380 : }
381 :
382 0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
383 : pub struct Tracing {
384 : pub sampling_ratio: Ratio,
385 : pub export_config: OtelExporterConfig,
386 : }
387 :
388 : impl From<&OtelExporterConfig> for tracing_utils::ExportConfig {
389 0 : fn from(val: &OtelExporterConfig) -> Self {
390 0 : tracing_utils::ExportConfig {
391 0 : endpoint: Some(val.endpoint.clone()),
392 0 : protocol: val.protocol.into(),
393 0 : timeout: val.timeout,
394 0 : }
395 0 : }
396 : }
397 :
398 : impl From<OtelExporterProtocol> for tracing_utils::Protocol {
399 0 : fn from(val: OtelExporterProtocol) -> Self {
400 0 : match val {
401 0 : OtelExporterProtocol::Grpc => tracing_utils::Protocol::Grpc,
402 0 : OtelExporterProtocol::HttpJson => tracing_utils::Protocol::HttpJson,
403 0 : OtelExporterProtocol::HttpBinary => tracing_utils::Protocol::HttpBinary,
404 : }
405 0 : }
406 : }
407 :
408 0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
409 : pub struct TimelineImportConfig {
410 : pub import_job_concurrency: NonZeroUsize,
411 : pub import_job_soft_size_limit: NonZeroUsize,
412 : pub import_job_checkpoint_threshold: NonZeroUsize,
413 : /// Max size of the remote storage partial read done by any job
414 : pub import_job_max_byte_range_size: NonZeroUsize,
415 : }
416 :
417 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
418 : #[serde(default)]
419 : pub struct BasebackupCacheConfig {
420 : #[serde(with = "humantime_serde")]
421 : pub cleanup_period: Duration,
422 : /// Maximum total size of basebackup cache entries on disk in bytes.
423 : /// The cache may slightly exceed this limit because we do not know
424 : /// the exact size of the cache entry untill it's written to disk.
425 : pub max_total_size_bytes: u64,
426 : // TODO(diko): support max_entry_size_bytes.
427 : // pub max_entry_size_bytes: u64,
428 : pub max_size_entries: usize,
429 : /// Size of the channel used to send prepare requests to the basebackup cache worker.
430 : /// If exceeded, new prepare requests will be dropped.
431 : pub prepare_channel_size: usize,
432 : }
433 :
434 : impl Default for BasebackupCacheConfig {
435 0 : fn default() -> Self {
436 0 : Self {
437 0 : cleanup_period: Duration::from_secs(60),
438 0 : max_total_size_bytes: 1024 * 1024 * 1024, // 1 GiB
439 0 : // max_entry_size_bytes: 16 * 1024 * 1024, // 16 MiB
440 0 : max_size_entries: 10000,
441 0 : prepare_channel_size: 100,
442 0 : }
443 0 : }
444 : }
445 :
446 : pub mod statvfs {
447 : pub mod mock {
448 0 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
449 : #[serde(tag = "type")]
450 : pub enum Behavior {
451 : Success {
452 : blocksize: u64,
453 : total_blocks: u64,
454 : name_filter: Option<utils::serde_regex::Regex>,
455 : },
456 : #[cfg(feature = "testing")]
457 : Failure { mocked_error: MockedError },
458 : }
459 :
460 : #[cfg(feature = "testing")]
461 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
462 : #[allow(clippy::upper_case_acronyms)]
463 : pub enum MockedError {
464 : EIO,
465 : }
466 :
467 : #[cfg(feature = "testing")]
468 : impl From<MockedError> for nix::Error {
469 0 : fn from(e: MockedError) -> Self {
470 0 : match e {
471 0 : MockedError::EIO => nix::Error::EIO,
472 : }
473 0 : }
474 : }
475 : }
476 : }
477 :
478 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
479 : #[serde(tag = "type", content = "args")]
480 : pub enum EvictionOrder {
481 : RelativeAccessed {
482 : highest_layer_count_loses_first: bool,
483 : },
484 : }
485 :
486 : impl Default for EvictionOrder {
487 143 : fn default() -> Self {
488 143 : Self::RelativeAccessed {
489 143 : highest_layer_count_loses_first: true,
490 143 : }
491 143 : }
492 : }
493 :
494 : #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
495 : #[serde(transparent)]
496 : pub struct MaxVectoredReadBytes(pub NonZeroUsize);
497 :
498 : #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
499 : #[serde(transparent)]
500 : pub struct MaxGetVectoredKeys(NonZeroUsize);
501 :
502 : impl MaxGetVectoredKeys {
503 71990 : pub fn get(&self) -> usize {
504 71990 : self.0.get()
505 71990 : }
506 : }
507 :
508 : /// Tenant-level configuration values, used for various purposes.
509 : #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
510 : #[serde(default)]
511 : pub struct TenantConfigToml {
512 : // Flush out an inmemory layer, if it's holding WAL older than this
513 : // This puts a backstop on how much WAL needs to be re-digested if the
514 : // page server crashes.
515 : // This parameter actually determines L0 layer file size.
516 : pub checkpoint_distance: u64,
517 : // Inmemory layer is also flushed at least once in checkpoint_timeout to
518 : // eventually upload WAL after activity is stopped.
519 : #[serde(with = "humantime_serde")]
520 : pub checkpoint_timeout: Duration,
521 : // Target file size, when creating image and delta layers.
522 : // This parameter determines L1 layer file size.
523 : pub compaction_target_size: u64,
524 : // How often to check if there's compaction work to be done.
525 : // Duration::ZERO means automatic compaction is disabled.
526 : #[serde(with = "humantime_serde")]
527 : pub compaction_period: Duration,
528 : /// Level0 delta layer threshold for compaction.
529 : pub compaction_threshold: usize,
530 : /// Controls the amount of L0 included in a single compaction iteration.
531 : /// The unit is `checkpoint_distance`, i.e., a size.
532 : /// We add L0s to the set of layers to compact until their cumulative
533 : /// size exceeds `compaction_upper_limit * checkpoint_distance`.
534 : pub compaction_upper_limit: usize,
535 : pub compaction_algorithm: crate::models::CompactionAlgorithmSettings,
536 : /// If true, enable shard ancestor compaction (enabled by default).
537 : pub compaction_shard_ancestor: bool,
538 : /// If true, compact down L0 across all tenant timelines before doing regular compaction. L0
539 : /// compaction must be responsive to avoid read amp during heavy ingestion. Defaults to true.
540 : pub compaction_l0_first: bool,
541 : /// If true, use a separate semaphore (i.e. concurrency limit) for the L0 compaction pass. Only
542 : /// has an effect if `compaction_l0_first` is true. Defaults to true.
543 : pub compaction_l0_semaphore: bool,
544 : /// Level0 delta layer threshold at which to delay layer flushes such that they take 2x as long,
545 : /// and block on layer flushes during ephemeral layer rolls, for compaction backpressure. This
546 : /// helps compaction keep up with WAL ingestion, and avoids read amplification blowing up.
547 : /// Should be >compaction_threshold. 0 to disable. Defaults to 3x compaction_threshold.
548 : pub l0_flush_delay_threshold: Option<usize>,
549 : /// Level0 delta layer threshold at which to stall layer flushes. Must be >compaction_threshold
550 : /// to avoid deadlock. 0 to disable. Disabled by default.
551 : pub l0_flush_stall_threshold: Option<usize>,
552 : // Determines how much history is retained, to allow
553 : // branching and read replicas at an older point in time.
554 : // The unit is #of bytes of WAL.
555 : // Page versions older than this are garbage collected away.
556 : pub gc_horizon: u64,
557 : // Interval at which garbage collection is triggered.
558 : // Duration::ZERO means automatic GC is disabled
559 : #[serde(with = "humantime_serde")]
560 : pub gc_period: Duration,
561 : // Delta layer churn threshold to create L1 image layers.
562 : pub image_creation_threshold: usize,
563 : // Determines how much history is retained, to allow
564 : // branching and read replicas at an older point in time.
565 : // The unit is time.
566 : // Page versions older than this are garbage collected away.
567 : #[serde(with = "humantime_serde")]
568 : pub pitr_interval: Duration,
569 : /// Maximum amount of time to wait while opening a connection to receive wal, before erroring.
570 : #[serde(with = "humantime_serde")]
571 : pub walreceiver_connect_timeout: Duration,
572 : /// Considers safekeepers stalled after no WAL updates were received longer than this threshold.
573 : /// A stalled safekeeper will be changed to a newer one when it appears.
574 : #[serde(with = "humantime_serde")]
575 : pub lagging_wal_timeout: Duration,
576 : /// Considers safekeepers lagging when their WAL is behind another safekeeper for more than this threshold.
577 : /// A lagging safekeeper will be changed after `lagging_wal_timeout` time elapses since the last WAL update,
578 : /// to avoid eager reconnects.
579 : pub max_lsn_wal_lag: NonZeroU64,
580 : pub eviction_policy: crate::models::EvictionPolicy,
581 : pub min_resident_size_override: Option<u64>,
582 : // See the corresponding metric's help string.
583 : #[serde(with = "humantime_serde")]
584 : pub evictions_low_residence_duration_metric_threshold: Duration,
585 :
586 : /// If non-zero, the period between uploads of a heatmap from attached tenants. This
587 : /// may be disabled if a Tenant will not have secondary locations: only secondary
588 : /// locations will use the heatmap uploaded by attached locations.
589 : #[serde(with = "humantime_serde")]
590 : pub heatmap_period: Duration,
591 :
592 : /// If true then SLRU segments are dowloaded on demand, if false SLRU segments are included in basebackup
593 : pub lazy_slru_download: bool,
594 :
595 : pub timeline_get_throttle: crate::models::ThrottleConfig,
596 :
597 : // How much WAL must be ingested before checking again whether a new image layer is required.
598 : // Expresed in multiples of checkpoint distance.
599 : pub image_layer_creation_check_threshold: u8,
600 :
601 : // How many multiples of L0 `compaction_threshold` will preempt image layer creation and do L0 compaction.
602 : // Set to 0 to disable preemption.
603 : pub image_creation_preempt_threshold: usize,
604 :
605 : /// The length for an explicit LSN lease request.
606 : /// Layers needed to reconstruct pages at LSN will not be GC-ed during this interval.
607 : #[serde(with = "humantime_serde")]
608 : pub lsn_lease_length: Duration,
609 :
610 : /// The length for an implicit LSN lease granted as part of `get_lsn_by_timestamp` request.
611 : /// Layers needed to reconstruct pages at LSN will not be GC-ed during this interval.
612 : #[serde(with = "humantime_serde")]
613 : pub lsn_lease_length_for_ts: Duration,
614 :
615 : /// Enable auto-offloading of timelines.
616 : /// (either this flag or the pageserver-global one need to be set)
617 : pub timeline_offloading: bool,
618 :
619 : /// Enable rel_size_v2 for this tenant. Once enabled, the tenant will persist this information into
620 : /// `index_part.json`, and it cannot be reversed.
621 : pub rel_size_v2_enabled: bool,
622 :
623 : // gc-compaction related configs
624 : /// Enable automatic gc-compaction trigger on this tenant.
625 : pub gc_compaction_enabled: bool,
626 : /// Enable verification of gc-compaction results.
627 : pub gc_compaction_verification: bool,
628 : /// The initial threshold for gc-compaction in KB. Once the total size of layers below the gc-horizon is above this threshold,
629 : /// gc-compaction will be triggered.
630 : pub gc_compaction_initial_threshold_kb: u64,
631 : /// 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)
632 : /// is above this ratio, gc-compaction will be triggered.
633 : pub gc_compaction_ratio_percent: u64,
634 : /// Tenant level performance sampling ratio override. Controls the ratio of get page requests
635 : /// that will get perf sampling for the tenant.
636 : pub sampling_ratio: Option<Ratio>,
637 :
638 : /// Capacity of relsize snapshot cache (used by replicas).
639 : pub relsize_snapshot_cache_capacity: usize,
640 :
641 : /// Enable preparing basebackup on XLOG_CHECKPOINT_SHUTDOWN and using it in basebackup requests.
642 : // FIXME: Remove skip_serializing_if when the feature is stable.
643 : #[serde(skip_serializing_if = "std::ops::Not::not")]
644 : pub basebackup_cache_enabled: bool,
645 : }
646 :
647 : pub mod defaults {
648 : pub use storage_broker::DEFAULT_ENDPOINT as BROKER_DEFAULT_ENDPOINT;
649 :
650 : use crate::models::ImageCompressionAlgorithm;
651 :
652 : pub const DEFAULT_WAIT_LSN_TIMEOUT: &str = "300 s";
653 : pub const DEFAULT_WAL_REDO_TIMEOUT: &str = "60 s";
654 :
655 : pub const DEFAULT_SUPERUSER: &str = "cloud_admin";
656 : pub const DEFAULT_LOCALE: &str = if cfg!(target_os = "macos") {
657 : "C"
658 : } else {
659 : "C.UTF-8"
660 : };
661 :
662 : pub const DEFAULT_PAGE_CACHE_SIZE: usize = 8192;
663 : pub const DEFAULT_MAX_FILE_DESCRIPTORS: usize = 100;
664 :
665 : pub const DEFAULT_LOG_FORMAT: &str = "plain";
666 :
667 : pub const DEFAULT_CONCURRENT_TENANT_WARMUP: usize = 8;
668 :
669 : pub const DEFAULT_CONCURRENT_TENANT_SIZE_LOGICAL_SIZE_QUERIES: usize = 1;
670 :
671 : pub const DEFAULT_METRIC_COLLECTION_INTERVAL: &str = "10 min";
672 : pub const DEFAULT_METRIC_COLLECTION_ENDPOINT: Option<reqwest::Url> = None;
673 : pub const DEFAULT_SYNTHETIC_SIZE_CALCULATION_INTERVAL: &str = "10 min";
674 : pub const DEFAULT_BACKGROUND_TASK_MAXIMUM_DELAY: &str = "10s";
675 :
676 : pub const DEFAULT_HEATMAP_UPLOAD_CONCURRENCY: usize = 8;
677 : pub const DEFAULT_SECONDARY_DOWNLOAD_CONCURRENCY: usize = 1;
678 :
679 : pub const DEFAULT_INGEST_BATCH_SIZE: u64 = 100;
680 :
681 : /// Soft limit for the maximum size of a vectored read.
682 : ///
683 : /// This is determined by the largest NeonWalRecord that can exist (minus dbdir and reldir keys
684 : /// which are bounded by the blob io limits only). As of this writing, that is a `NeonWalRecord::ClogSetCommitted` record,
685 : /// with 32k xids. That's the max number of XIDS on a single CLOG page. The size of such a record
686 : /// is `sizeof(Transactionid) * 32768 + (some fixed overhead from 'timestamp`, the Vec length and whatever extra serde serialization adds)`.
687 : /// That is, slightly above 128 kB.
688 : pub const DEFAULT_MAX_VECTORED_READ_BYTES: usize = 130 * 1024; // 130 KiB
689 :
690 : pub const DEFAULT_MAX_GET_VECTORED_KEYS: usize = 32;
691 :
692 : pub const DEFAULT_IMAGE_COMPRESSION: ImageCompressionAlgorithm =
693 : ImageCompressionAlgorithm::Zstd { level: Some(1) };
694 :
695 : pub const DEFAULT_EPHEMERAL_BYTES_PER_MEMORY_KB: usize = 0;
696 :
697 : pub const DEFAULT_IO_BUFFER_ALIGNMENT: usize = 512;
698 :
699 : pub const DEFAULT_SSL_KEY_FILE: &str = "server.key";
700 : pub const DEFAULT_SSL_CERT_FILE: &str = "server.crt";
701 : }
702 :
703 : impl Default for ConfigToml {
704 137 : fn default() -> Self {
705 : use defaults::*;
706 :
707 : Self {
708 137 : listen_pg_addr: (DEFAULT_PG_LISTEN_ADDR.to_string()),
709 137 : listen_http_addr: (DEFAULT_HTTP_LISTEN_ADDR.to_string()),
710 137 : listen_https_addr: (None),
711 137 : listen_grpc_addr: None, // TODO: default to 127.0.0.1:51051
712 137 : ssl_key_file: Utf8PathBuf::from(DEFAULT_SSL_KEY_FILE),
713 137 : ssl_cert_file: Utf8PathBuf::from(DEFAULT_SSL_CERT_FILE),
714 137 : ssl_cert_reload_period: Duration::from_secs(60),
715 137 : ssl_ca_file: None,
716 137 : availability_zone: (None),
717 137 : wait_lsn_timeout: (humantime::parse_duration(DEFAULT_WAIT_LSN_TIMEOUT)
718 137 : .expect("cannot parse default wait lsn timeout")),
719 137 : wal_redo_timeout: (humantime::parse_duration(DEFAULT_WAL_REDO_TIMEOUT)
720 137 : .expect("cannot parse default wal redo timeout")),
721 137 : superuser: (DEFAULT_SUPERUSER.to_string()),
722 137 : locale: DEFAULT_LOCALE.to_string(),
723 : page_cache_size: (DEFAULT_PAGE_CACHE_SIZE),
724 : max_file_descriptors: (DEFAULT_MAX_FILE_DESCRIPTORS),
725 137 : pg_distrib_dir: None, // Utf8PathBuf::from("./pg_install"), // TODO: formely, this was std::env::current_dir()
726 137 : http_auth_type: (AuthType::Trust),
727 137 : pg_auth_type: (AuthType::Trust),
728 137 : grpc_auth_type: (AuthType::Trust),
729 137 : auth_validation_public_key_path: (None),
730 137 : remote_storage: None,
731 137 : broker_endpoint: (storage_broker::DEFAULT_ENDPOINT
732 137 : .parse()
733 137 : .expect("failed to parse default broker endpoint")),
734 137 : broker_keepalive_interval: (humantime::parse_duration(
735 137 : storage_broker::DEFAULT_KEEPALIVE_INTERVAL,
736 : )
737 137 : .expect("cannot parse default keepalive interval")),
738 137 : log_format: (LogFormat::from_str(DEFAULT_LOG_FORMAT).unwrap()),
739 :
740 137 : concurrent_tenant_warmup: (NonZeroUsize::new(DEFAULT_CONCURRENT_TENANT_WARMUP)
741 137 : .expect("Invalid default constant")),
742 137 : concurrent_tenant_size_logical_size_queries: NonZeroUsize::new(
743 : DEFAULT_CONCURRENT_TENANT_SIZE_LOGICAL_SIZE_QUERIES,
744 : )
745 137 : .unwrap(),
746 137 : metric_collection_interval: (humantime::parse_duration(
747 137 : DEFAULT_METRIC_COLLECTION_INTERVAL,
748 : )
749 137 : .expect("cannot parse default metric collection interval")),
750 137 : synthetic_size_calculation_interval: (humantime::parse_duration(
751 137 : DEFAULT_SYNTHETIC_SIZE_CALCULATION_INTERVAL,
752 : )
753 137 : .expect("cannot parse default synthetic size calculation interval")),
754 137 : metric_collection_endpoint: (DEFAULT_METRIC_COLLECTION_ENDPOINT),
755 :
756 137 : metric_collection_bucket: (None),
757 :
758 137 : disk_usage_based_eviction: DiskUsageEvictionTaskConfig::default(),
759 :
760 : test_remote_failures: (0),
761 :
762 : ondemand_download_behavior_treat_error_as_warn: (false),
763 :
764 137 : background_task_maximum_delay: (humantime::parse_duration(
765 137 : DEFAULT_BACKGROUND_TASK_MAXIMUM_DELAY,
766 : )
767 137 : .unwrap()),
768 :
769 137 : control_plane_api: (None),
770 137 : control_plane_api_token: (None),
771 : control_plane_emergency_mode: (false),
772 :
773 137 : import_pgdata_upcall_api: (None),
774 137 : import_pgdata_upcall_api_token: (None),
775 137 : import_pgdata_aws_endpoint_url: (None),
776 :
777 : heatmap_upload_concurrency: (DEFAULT_HEATMAP_UPLOAD_CONCURRENCY),
778 : secondary_download_concurrency: (DEFAULT_SECONDARY_DOWNLOAD_CONCURRENCY),
779 :
780 : ingest_batch_size: (DEFAULT_INGEST_BATCH_SIZE),
781 :
782 137 : virtual_file_io_engine: None,
783 :
784 137 : max_vectored_read_bytes: (MaxVectoredReadBytes(
785 137 : NonZeroUsize::new(DEFAULT_MAX_VECTORED_READ_BYTES).unwrap(),
786 137 : )),
787 137 : max_get_vectored_keys: (MaxGetVectoredKeys(
788 137 : NonZeroUsize::new(DEFAULT_MAX_GET_VECTORED_KEYS).unwrap(),
789 137 : )),
790 : image_compression: (DEFAULT_IMAGE_COMPRESSION),
791 : timeline_offloading: true,
792 : ephemeral_bytes_per_memory_kb: (DEFAULT_EPHEMERAL_BYTES_PER_MEMORY_KB),
793 137 : l0_flush: None,
794 137 : virtual_file_io_mode: None,
795 137 : tenant_config: TenantConfigToml::default(),
796 137 : no_sync: None,
797 137 : page_service_pipelining: PageServicePipeliningConfig::Pipelined(
798 137 : PageServicePipeliningConfigPipelined {
799 137 : max_batch_size: NonZeroUsize::new(32).unwrap(),
800 137 : execution: PageServiceProtocolPipelinedExecutionStrategy::ConcurrentFutures,
801 137 : batching: PageServiceProtocolPipelinedBatchingStrategy::ScatteredLsn,
802 137 : },
803 137 : ),
804 137 : get_vectored_concurrent_io: GetVectoredConcurrentIo::SidecarTask,
805 137 : enable_read_path_debugging: if cfg!(feature = "testing") {
806 137 : Some(true)
807 : } else {
808 0 : None
809 : },
810 137 : validate_wal_contiguity: None,
811 137 : load_previous_heatmap: None,
812 137 : generate_unarchival_heatmap: None,
813 137 : tracing: None,
814 : enable_tls_page_service_api: false,
815 : dev_mode: false,
816 137 : timeline_import_config: TimelineImportConfig {
817 137 : import_job_concurrency: NonZeroUsize::new(32).unwrap(),
818 137 : import_job_soft_size_limit: NonZeroUsize::new(256 * 1024 * 1024).unwrap(),
819 137 : import_job_checkpoint_threshold: NonZeroUsize::new(32).unwrap(),
820 137 : import_job_max_byte_range_size: NonZeroUsize::new(4 * 1024 * 1024).unwrap(),
821 137 : },
822 137 : basebackup_cache_config: None,
823 137 : posthog_config: None,
824 : }
825 137 : }
826 : }
827 :
828 : pub mod tenant_conf_defaults {
829 :
830 : // FIXME: This current value is very low. I would imagine something like 1 GB or 10 GB
831 : // would be more appropriate. But a low value forces the code to be exercised more,
832 : // which is good for now to trigger bugs.
833 : // This parameter actually determines L0 layer file size.
834 : pub const DEFAULT_CHECKPOINT_DISTANCE: u64 = 256 * 1024 * 1024;
835 : pub const DEFAULT_CHECKPOINT_TIMEOUT: &str = "10 m";
836 :
837 : // FIXME the below configs are only used by legacy algorithm. The new algorithm
838 : // has different parameters.
839 :
840 : // Target file size, when creating image and delta layers.
841 : // This parameter determines L1 layer file size.
842 : pub const DEFAULT_COMPACTION_TARGET_SIZE: u64 = 128 * 1024 * 1024;
843 :
844 : pub const DEFAULT_COMPACTION_PERIOD: &str = "20 s";
845 : pub const DEFAULT_COMPACTION_THRESHOLD: usize = 10;
846 : pub const DEFAULT_COMPACTION_SHARD_ANCESTOR: bool = true;
847 :
848 : // This value needs to be tuned to avoid OOM. We have 3/4*CPUs threads for L0 compaction, that's
849 : // 3/4*8=6 on most of our pageservers. Compacting 10 layers requires a maximum of
850 : // DEFAULT_CHECKPOINT_DISTANCE*10 memory, that's 2560MB. So with this config, we can get a maximum peak
851 : // compaction usage of 15360MB.
852 : pub const DEFAULT_COMPACTION_UPPER_LIMIT: usize = 10;
853 : // Enable L0 compaction pass and semaphore by default. L0 compaction must be responsive to avoid
854 : // read amp.
855 : pub const DEFAULT_COMPACTION_L0_FIRST: bool = true;
856 : pub const DEFAULT_COMPACTION_L0_SEMAPHORE: bool = true;
857 :
858 : pub const DEFAULT_COMPACTION_ALGORITHM: crate::models::CompactionAlgorithm =
859 : crate::models::CompactionAlgorithm::Legacy;
860 :
861 : pub const DEFAULT_GC_HORIZON: u64 = 64 * 1024 * 1024;
862 :
863 : // Large DEFAULT_GC_PERIOD is fine as long as PITR_INTERVAL is larger.
864 : // If there's a need to decrease this value, first make sure that GC
865 : // doesn't hold a layer map write lock for non-trivial operations.
866 : // Relevant: https://github.com/neondatabase/neon/issues/3394
867 : pub const DEFAULT_GC_PERIOD: &str = "1 hr";
868 : pub const DEFAULT_IMAGE_CREATION_THRESHOLD: usize = 3;
869 : // Currently, any value other than 0 will trigger image layer creation preemption immediately with L0 backpressure
870 : // without looking at the exact number of L0 layers.
871 : // It was expected to have the following behavior:
872 : // > If there are more than threshold * compaction_threshold (that is 3 * 10 in the default config) L0 layers, image
873 : // > layer creation will end immediately. Set to 0 to disable.
874 : pub const DEFAULT_IMAGE_CREATION_PREEMPT_THRESHOLD: usize = 3;
875 : pub const DEFAULT_PITR_INTERVAL: &str = "7 days";
876 : pub const DEFAULT_WALRECEIVER_CONNECT_TIMEOUT: &str = "10 seconds";
877 : pub const DEFAULT_WALRECEIVER_LAGGING_WAL_TIMEOUT: &str = "10 seconds";
878 : // The default limit on WAL lag should be set to avoid causing disconnects under high throughput
879 : // scenarios: since the broker stats are updated ~1/s, a value of 1GiB should be sufficient for
880 : // throughputs up to 1GiB/s per timeline.
881 : pub const DEFAULT_MAX_WALRECEIVER_LSN_WAL_LAG: u64 = 1024 * 1024 * 1024;
882 : pub const DEFAULT_EVICTIONS_LOW_RESIDENCE_DURATION_METRIC_THRESHOLD: &str = "24 hour";
883 : // By default ingest enough WAL for two new L0 layers before checking if new image
884 : // image layers should be created.
885 : pub const DEFAULT_IMAGE_LAYER_CREATION_CHECK_THRESHOLD: u8 = 2;
886 : pub const DEFAULT_GC_COMPACTION_ENABLED: bool = true;
887 : pub const DEFAULT_GC_COMPACTION_VERIFICATION: bool = true;
888 : pub const DEFAULT_GC_COMPACTION_INITIAL_THRESHOLD_KB: u64 = 5 * 1024 * 1024; // 5GB
889 : pub const DEFAULT_GC_COMPACTION_RATIO_PERCENT: u64 = 100;
890 : pub const DEFAULT_RELSIZE_SNAPSHOT_CACHE_CAPACITY: usize = 1000;
891 : }
892 :
893 : impl Default for TenantConfigToml {
894 137 : fn default() -> Self {
895 : use tenant_conf_defaults::*;
896 137 : Self {
897 137 : checkpoint_distance: DEFAULT_CHECKPOINT_DISTANCE,
898 137 : checkpoint_timeout: humantime::parse_duration(DEFAULT_CHECKPOINT_TIMEOUT)
899 137 : .expect("cannot parse default checkpoint timeout"),
900 137 : compaction_target_size: DEFAULT_COMPACTION_TARGET_SIZE,
901 137 : compaction_period: humantime::parse_duration(DEFAULT_COMPACTION_PERIOD)
902 137 : .expect("cannot parse default compaction period"),
903 137 : compaction_threshold: DEFAULT_COMPACTION_THRESHOLD,
904 137 : compaction_upper_limit: DEFAULT_COMPACTION_UPPER_LIMIT,
905 137 : compaction_algorithm: crate::models::CompactionAlgorithmSettings {
906 137 : kind: DEFAULT_COMPACTION_ALGORITHM,
907 137 : },
908 137 : compaction_shard_ancestor: DEFAULT_COMPACTION_SHARD_ANCESTOR,
909 137 : compaction_l0_first: DEFAULT_COMPACTION_L0_FIRST,
910 137 : compaction_l0_semaphore: DEFAULT_COMPACTION_L0_SEMAPHORE,
911 137 : l0_flush_delay_threshold: None,
912 137 : l0_flush_stall_threshold: None,
913 137 : gc_horizon: DEFAULT_GC_HORIZON,
914 137 : gc_period: humantime::parse_duration(DEFAULT_GC_PERIOD)
915 137 : .expect("cannot parse default gc period"),
916 137 : image_creation_threshold: DEFAULT_IMAGE_CREATION_THRESHOLD,
917 137 : pitr_interval: humantime::parse_duration(DEFAULT_PITR_INTERVAL)
918 137 : .expect("cannot parse default PITR interval"),
919 137 : walreceiver_connect_timeout: humantime::parse_duration(
920 137 : DEFAULT_WALRECEIVER_CONNECT_TIMEOUT,
921 137 : )
922 137 : .expect("cannot parse default walreceiver connect timeout"),
923 137 : lagging_wal_timeout: humantime::parse_duration(DEFAULT_WALRECEIVER_LAGGING_WAL_TIMEOUT)
924 137 : .expect("cannot parse default walreceiver lagging wal timeout"),
925 137 : max_lsn_wal_lag: NonZeroU64::new(DEFAULT_MAX_WALRECEIVER_LSN_WAL_LAG)
926 137 : .expect("cannot parse default max walreceiver Lsn wal lag"),
927 137 : eviction_policy: crate::models::EvictionPolicy::NoEviction,
928 137 : min_resident_size_override: None,
929 137 : evictions_low_residence_duration_metric_threshold: humantime::parse_duration(
930 137 : DEFAULT_EVICTIONS_LOW_RESIDENCE_DURATION_METRIC_THRESHOLD,
931 137 : )
932 137 : .expect("cannot parse default evictions_low_residence_duration_metric_threshold"),
933 137 : heatmap_period: Duration::ZERO,
934 137 : lazy_slru_download: false,
935 137 : timeline_get_throttle: crate::models::ThrottleConfig::disabled(),
936 137 : image_layer_creation_check_threshold: DEFAULT_IMAGE_LAYER_CREATION_CHECK_THRESHOLD,
937 137 : image_creation_preempt_threshold: DEFAULT_IMAGE_CREATION_PREEMPT_THRESHOLD,
938 137 : lsn_lease_length: LsnLease::DEFAULT_LENGTH,
939 137 : lsn_lease_length_for_ts: LsnLease::DEFAULT_LENGTH_FOR_TS,
940 137 : timeline_offloading: true,
941 137 : rel_size_v2_enabled: false,
942 137 : gc_compaction_enabled: DEFAULT_GC_COMPACTION_ENABLED,
943 137 : gc_compaction_verification: DEFAULT_GC_COMPACTION_VERIFICATION,
944 137 : gc_compaction_initial_threshold_kb: DEFAULT_GC_COMPACTION_INITIAL_THRESHOLD_KB,
945 137 : gc_compaction_ratio_percent: DEFAULT_GC_COMPACTION_RATIO_PERCENT,
946 137 : sampling_ratio: None,
947 137 : relsize_snapshot_cache_capacity: DEFAULT_RELSIZE_SNAPSHOT_CACHE_CAPACITY,
948 137 : basebackup_cache_enabled: false,
949 137 : }
950 137 : }
951 : }
|