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