1#![allow(missing_docs)]
11
12use std::sync::Arc;
22use std::sync::atomic::AtomicBool;
23use std::time::{Duration, SystemTime, UNIX_EPOCH};
24
25use mz_build_info::BuildInfo;
26use mz_dyncfg::{Config, ConfigDefault, ConfigSet, ConfigUpdates, ParameterScope};
27use mz_ore::instrument;
28use mz_ore::now::NowFn;
29use mz_persist::cfg::BlobKnobs;
30use mz_persist::retry::Retry;
31use mz_postgres_client::PostgresClientKnobs;
32use proptest_derive::Arbitrary;
33use semver::Version;
34use serde::{Deserialize, Serialize};
35use tokio::sync::watch;
36
37use crate::async_runtime;
38use crate::internal::machine::{
39 NEXT_LISTEN_BATCH_RETRYER_CLAMP, NEXT_LISTEN_BATCH_RETRYER_INITIAL_BACKOFF,
40 NEXT_LISTEN_BATCH_RETRYER_MULTIPLIER,
41};
42use crate::internal::state::ROLLUP_THRESHOLD;
43use crate::operators::STORAGE_SOURCE_DECODE_FUEL;
44use crate::read::READER_LEASE_DURATION;
45
46const SELF_MANAGED_VERSIONS: &[Version; 2] = &[
48 Version::new(0, 130, 0),
50 Version::new(0, 147, 0),
52];
53
54#[derive(Debug, Clone)]
106pub struct PersistConfig {
107 pub build_version: Version,
109 pub hostname: String,
112 pub is_cc_active: bool,
114 pub announce_memory_limit: Option<usize>,
116 pub now: NowFn,
118 pub configs: Arc<ConfigSet>,
123 configs_synced_once: Arc<watch::Sender<bool>>,
126 pub compaction_enabled: bool,
128 pub compaction_process_requests: Arc<AtomicBool>,
130 pub compaction_concurrency_limit: usize,
133 pub compaction_queue_size: usize,
136 pub compaction_yield_after_n_updates: usize,
139 pub writer_lease_duration: Duration,
142 pub critical_downgrade_interval: Duration,
144 pub isolated_runtime_worker_threads: usize,
147}
148
149impl std::ops::Deref for PersistConfig {
151 type Target = ConfigSet;
152 fn deref(&self) -> &Self::Target {
153 &self.configs
154 }
155}
156
157impl PersistConfig {
158 pub fn new_default_configs(build_info: &BuildInfo, now: NowFn) -> Self {
161 Self::new(build_info, now, all_dyncfgs(ConfigSet::default()))
162 }
163
164 pub fn new(build_info: &BuildInfo, now: NowFn, configs: ConfigSet) -> Self {
167 let compaction_disabled = mz_ore::env::is_var_truthy("MZ_PERSIST_COMPACTION_DISABLED");
169
170 let (configs_synced_once, _) = watch::channel(false);
172
173 Self {
174 build_version: build_info.semver_version(),
175 is_cc_active: false,
176 announce_memory_limit: None,
177 now,
178 configs: Arc::new(configs),
179 configs_synced_once: Arc::new(configs_synced_once),
180 compaction_enabled: !compaction_disabled,
181 compaction_process_requests: Arc::new(AtomicBool::new(true)),
182 compaction_concurrency_limit: 5,
183 compaction_queue_size: 20,
184 compaction_yield_after_n_updates: 100_000,
185 writer_lease_duration: 60 * Duration::from_secs(60),
186 critical_downgrade_interval: Duration::from_secs(30),
187 isolated_runtime_worker_threads: num_cpus::get(),
188 hostname: {
193 use std::fmt::Write;
194 let mut name = std::env::var("HOSTNAME").unwrap_or_else(|_| "unknown".to_owned());
195 write!(&mut name, " {}", build_info.version)
196 .expect("writing to string should not fail");
197 name
198 },
199 }
200 }
201
202 pub(crate) fn set_config<T: ConfigDefault>(&self, cfg: &Config<T>, val: T) {
203 let mut updates = ConfigUpdates::default();
204 updates.add(cfg, val);
205 updates.apply(self)
206 }
207
208 pub fn apply_from(&self, updates: &ConfigUpdates) {
214 updates.apply(&self.configs);
215 self.configs_synced_once.send_replace(true);
216 }
217
218 #[instrument(level = "info")]
227 pub async fn configs_synced_once(&self) {
228 self.configs_synced_once
229 .subscribe()
230 .wait_for(|synced| *synced)
231 .await
232 .expect("we have a borrow on sender so it cannot drop");
233 }
234
235 pub fn storage_source_decode_fuel(&self) -> usize {
238 STORAGE_SOURCE_DECODE_FUEL.get(self)
239 }
240
241 pub fn set_reader_lease_duration(&self, val: Duration) {
243 self.set_config(&READER_LEASE_DURATION, val);
244 }
245
246 pub fn set_rollup_threshold(&self, val: usize) {
248 self.set_config(&ROLLUP_THRESHOLD, val);
249 }
250
251 pub fn set_next_listen_batch_retryer(&self, val: RetryParameters) {
254 self.set_config(
255 &NEXT_LISTEN_BATCH_RETRYER_INITIAL_BACKOFF,
256 val.initial_backoff,
257 );
258 self.set_config(&NEXT_LISTEN_BATCH_RETRYER_MULTIPLIER, val.multiplier);
259 self.set_config(&NEXT_LISTEN_BATCH_RETRYER_CLAMP, val.clamp);
260 }
261
262 pub fn disable_compaction(&self) {
263 tracing::info!("Disabling Persist Compaction");
264 self.compaction_process_requests
265 .store(false, std::sync::atomic::Ordering::Relaxed);
266 }
267
268 pub fn enable_compaction(&self) {
269 tracing::info!("Enabling Persist Compaction");
270 self.compaction_process_requests
271 .store(true, std::sync::atomic::Ordering::Relaxed);
272 }
273
274 pub fn new_for_tests() -> Self {
276 use mz_build_info::DUMMY_BUILD_INFO;
277 use mz_ore::now::SYSTEM_TIME;
278
279 let mut cfg = Self::new_default_configs(&DUMMY_BUILD_INFO, SYSTEM_TIME.clone());
280 cfg.hostname = "tests".into();
281 cfg.isolated_runtime_worker_threads = async_runtime::TEST_THREADS;
282 cfg
283 }
284}
285
286#[allow(non_upper_case_globals)]
287pub(crate) const MiB: usize = 1024 * 1024;
288
289pub fn all_dyncfgs(configs: ConfigSet) -> ConfigSet {
304 mz_persist::cfg::all_dyn_configs(configs)
305 .add(&crate::batch::BATCH_DELETE_ENABLED)
306 .add(&crate::batch::BLOB_TARGET_SIZE)
307 .add(&crate::batch::INLINE_WRITES_TOTAL_MAX_BYTES)
308 .add(&crate::batch::INLINE_WRITES_SINGLE_MAX_BYTES)
309 .add(&crate::batch::ENCODING_ENABLE_DICTIONARY)
310 .add(&crate::batch::ENCODING_COMPRESSION_FORMAT)
311 .add(&crate::batch::STRUCTURED_KEY_LOWER_LEN)
312 .add(&crate::batch::MAX_RUN_LEN)
313 .add(&crate::batch::MAX_RUNS)
314 .add(&BLOB_OPERATION_TIMEOUT)
315 .add(&BLOB_OPERATION_ATTEMPT_TIMEOUT)
316 .add(&BLOB_CONNECT_TIMEOUT)
317 .add(&BLOB_READ_TIMEOUT)
318 .add(&crate::cfg::CONSENSUS_CONNECTION_POOL_MAX_SIZE)
319 .add(&crate::cfg::CONSENSUS_CONNECTION_POOL_MAX_WAIT)
320 .add(&crate::cfg::CONSENSUS_CONNECTION_POOL_TTL_STAGGER)
321 .add(&crate::cfg::CONSENSUS_CONNECTION_POOL_TTL)
322 .add(&crate::cfg::CRDB_CONNECT_TIMEOUT)
323 .add(&crate::cfg::CRDB_TCP_USER_TIMEOUT)
324 .add(&crate::cfg::CRDB_KEEPALIVES_IDLE)
325 .add(&crate::cfg::CRDB_KEEPALIVES_INTERVAL)
326 .add(&crate::cfg::CRDB_KEEPALIVES_RETRIES)
327 .add(&crate::cfg::USE_CRITICAL_SINCE_TXN)
328 .add(&crate::cfg::USE_CRITICAL_SINCE_CATALOG)
329 .add(&crate::cfg::USE_CRITICAL_SINCE_SOURCE)
330 .add(&crate::cfg::USE_CRITICAL_SINCE_SNAPSHOT)
331 .add(&crate::cfg::SOURCE_HYDRATION_FRONTIER_COALESCE_BYTES)
332 .add(&crate::cfg::SOURCE_FETCH_CONCURRENCY)
333 .add(&BATCH_BUILDER_MAX_OUTSTANDING_PARTS)
334 .add(&COMPACTION_HEURISTIC_MIN_INPUTS)
335 .add(&COMPACTION_HEURISTIC_MIN_PARTS)
336 .add(&COMPACTION_HEURISTIC_MIN_UPDATES)
337 .add(&COMPACTION_MEMORY_BOUND_BYTES)
338 .add(&GC_BLOB_DELETE_CONCURRENCY_LIMIT)
339 .add(&STATE_VERSIONS_RECENT_LIVE_DIFFS_LIMIT)
340 .add(&USAGE_STATE_FETCH_CONCURRENCY_LIMIT)
341 .add(&crate::cache::STATE_UPDATE_LEASE_TIMEOUT)
342 .add(&crate::cli::admin::CATALOG_FORCE_COMPACTION_FUEL)
343 .add(&crate::cli::admin::CATALOG_FORCE_COMPACTION_WAIT)
344 .add(&crate::cli::admin::EXPRESSION_CACHE_FORCE_COMPACTION_FUEL)
345 .add(&crate::cli::admin::EXPRESSION_CACHE_FORCE_COMPACTION_WAIT)
346 .add(&crate::fetch::FETCH_SEMAPHORE_COST_ADJUSTMENT)
347 .add(&crate::fetch::FETCH_SEMAPHORE_PERMIT_ADJUSTMENT)
348 .add(&crate::fetch::VALIDATE_PART_BOUNDS_ON_READ)
349 .add(&crate::fetch::OPTIMIZE_IGNORED_DATA_FETCH)
350 .add(&crate::internal::cache::BLOB_CACHE_MEM_LIMIT_BYTES)
351 .add(&crate::internal::cache::BLOB_CACHE_SCALE_WITH_THREADS)
352 .add(&crate::internal::cache::BLOB_CACHE_SCALE_FACTOR_BYTES)
353 .add(&crate::internal::compact::COMPACTION_MINIMUM_TIMEOUT)
354 .add(&crate::internal::compact::COMPACTION_CHECK_PROCESS_FLAG)
355 .add(&crate::internal::machine::CLAIM_UNCLAIMED_COMPACTIONS)
356 .add(&crate::internal::machine::CLAIM_COMPACTION_PERCENT)
357 .add(&crate::internal::machine::CLAIM_COMPACTION_MIN_VERSION)
358 .add(&crate::internal::machine::NEXT_LISTEN_BATCH_RETRYER_CLAMP)
359 .add(&crate::internal::machine::NEXT_LISTEN_BATCH_RETRYER_FIXED_SLEEP)
360 .add(&crate::internal::machine::NEXT_LISTEN_BATCH_RETRYER_INITIAL_BACKOFF)
361 .add(&crate::internal::machine::NEXT_LISTEN_BATCH_RETRYER_MULTIPLIER)
362 .add(&crate::internal::state::ROLLUP_THRESHOLD)
363 .add(&crate::internal::state::ROLLUP_USE_ACTIVE_ROLLUP)
364 .add(&crate::internal::state::GC_FALLBACK_THRESHOLD_MS)
365 .add(&crate::internal::state::GC_USE_ACTIVE_GC)
366 .add(&crate::internal::state::GC_MIN_VERSIONS)
367 .add(&crate::internal::state::GC_MAX_VERSIONS)
368 .add(&crate::internal::state::ROLLUP_FALLBACK_THRESHOLD_MS)
369 .add(&crate::internal::state::ENABLE_INCREMENTAL_COMPACTION)
370 .add(&crate::operators::STORAGE_SOURCE_DECODE_FUEL)
371 .add(&crate::read::READER_LEASE_DURATION)
372 .add(&crate::rpc::PUBSUB_CLIENT_ENABLED)
373 .add(&crate::rpc::PUBSUB_PUSH_DIFF_ENABLED)
374 .add(&crate::rpc::PUBSUB_SAME_PROCESS_DELEGATE_ENABLED)
375 .add(&crate::rpc::PUBSUB_CONNECT_ATTEMPT_TIMEOUT)
376 .add(&crate::rpc::PUBSUB_REQUEST_TIMEOUT)
377 .add(&crate::rpc::PUBSUB_CONNECT_MAX_BACKOFF)
378 .add(&crate::rpc::PUBSUB_CLIENT_SENDER_CHANNEL_SIZE)
379 .add(&crate::rpc::PUBSUB_CLIENT_RECEIVER_CHANNEL_SIZE)
380 .add(&crate::rpc::PUBSUB_SERVER_CONNECTION_CHANNEL_SIZE)
381 .add(&crate::rpc::PUBSUB_STATE_CACHE_SHARD_REF_CHANNEL_SIZE)
382 .add(&crate::rpc::PUBSUB_RECONNECT_BACKOFF)
383 .add(&crate::stats::STATS_AUDIT_PERCENT)
384 .add(&crate::stats::STATS_AUDIT_PANIC)
385 .add(&crate::stats::STATS_BUDGET_BYTES)
386 .add(&crate::stats::STATS_COLLECTION_ENABLED)
387 .add(&crate::stats::STATS_FILTER_ENABLED)
388 .add(&crate::stats::STATS_UNTRIMMABLE_COLUMNS_EQUALS)
389 .add(&crate::stats::STATS_UNTRIMMABLE_COLUMNS_PREFIX)
390 .add(&crate::stats::STATS_UNTRIMMABLE_COLUMNS_SUFFIX)
391 .add(&crate::fetch::PART_DECODE_FORMAT)
392 .add(&crate::write::COMBINE_INLINE_WRITES)
393 .add(&crate::write::VALIDATE_PART_BOUNDS_ON_WRITE)
394}
395
396impl PersistConfig {
397 pub(crate) const DEFAULT_FALLBACK_ROLLUP_THRESHOLD_MULTIPLIER: usize = 3;
398
399 pub fn set_state_versions_recent_live_diffs_limit(&self, val: usize) {
400 self.set_config(&STATE_VERSIONS_RECENT_LIVE_DIFFS_LIMIT, val);
401 }
402}
403
404pub const CONSENSUS_CONNECTION_POOL_MAX_SIZE: Config<usize> = Config::new(
408 "persist_consensus_connection_pool_max_size",
409 50,
410 "The maximum size the connection pool to Postgres/CRDB will grow to.",
411 ParameterScope::Environment,
412);
413
414const CONSENSUS_CONNECTION_POOL_MAX_WAIT: Config<Duration> = Config::new(
419 "persist_consensus_connection_pool_max_wait",
420 Duration::from_secs(60),
421 "The amount of time we'll wait for a connection to become available.",
422 ParameterScope::Environment,
423);
424
425const CONSENSUS_CONNECTION_POOL_TTL: Config<Duration> = Config::new(
429 "persist_consensus_connection_pool_ttl",
430 Duration::from_secs(300),
431 "\
432 The minimum TTL of a Consensus connection to Postgres/CRDB before it is \
433 proactively terminated",
434 ParameterScope::Environment,
435);
436
437const CONSENSUS_CONNECTION_POOL_TTL_STAGGER: Config<Duration> = Config::new(
445 "persist_consensus_connection_pool_ttl_stagger",
446 Duration::from_secs(6),
447 "The minimum time between TTLing Consensus connections to Postgres/CRDB.",
448 ParameterScope::Environment,
449);
450
451pub const CRDB_CONNECT_TIMEOUT: Config<Duration> = Config::new(
454 "crdb_connect_timeout",
455 Duration::from_secs(5),
456 "The time to connect to CockroachDB before timing out and retrying.",
457 ParameterScope::Environment,
458);
459
460pub const CRDB_TCP_USER_TIMEOUT: Config<Duration> = Config::new(
464 "crdb_tcp_user_timeout",
465 Duration::from_secs(30),
466 "\
467 The TCP timeout for connections to CockroachDB. Specifies the amount of \
468 time that transmitted data may remain unacknowledged before the TCP \
469 connection is forcibly closed.",
470 ParameterScope::Environment,
471);
472
473pub const CRDB_KEEPALIVES_IDLE: Config<Duration> = Config::new(
474 "crdb_keepalives_idle",
475 Duration::from_secs(10),
476 "\
477 The amount of idle time before a TCP keepalive packet is sent on CRDB \
478 connections.",
479 ParameterScope::Environment,
480);
481
482pub const CRDB_KEEPALIVES_INTERVAL: Config<Duration> = Config::new(
483 "crdb_keepalives_interval",
484 Duration::from_secs(5),
485 "The time interval between TCP keepalive probes on CRDB connections.",
486 ParameterScope::Environment,
487);
488
489pub const CRDB_KEEPALIVES_RETRIES: Config<u32> = Config::new(
490 "crdb_keepalives_retries",
491 5,
492 "\
493 The maximum number of TCP keepalive probes that will be sent before \
494 dropping a CRDB connection.",
495 ParameterScope::Environment,
496);
497
498pub const USE_CRITICAL_SINCE_TXN: Config<bool> = Config::new(
500 "persist_use_critical_since_txn",
501 true,
502 "Use the critical since (instead of the overall since) when initializing a subscribe.",
503 ParameterScope::Environment,
504);
505
506pub const USE_CRITICAL_SINCE_CATALOG: Config<bool> = Config::new(
508 "persist_use_critical_since_catalog",
509 false,
510 "Use the critical since (instead of the overall since) for the Persist-backed catalog.",
511 ParameterScope::Environment,
512);
513
514pub const USE_CRITICAL_SINCE_SOURCE: Config<bool> = Config::new(
516 "persist_use_critical_since_source",
517 false,
518 "Use the critical since (instead of the overall since) in the Persist source.",
519 ParameterScope::Environment,
520);
521
522pub const SOURCE_HYDRATION_FRONTIER_COALESCE_BYTES: Config<usize> = Config::new(
527 "persist_source_hydration_frontier_coalesce_bytes",
528 0,
529 "While catching up to the hydration-time upper, the persist source coalesces \
530 frontier downgrades until this many encoded bytes have been emitted (0 disables).",
531 ParameterScope::Environment,
532);
533
534pub const SOURCE_FETCH_CONCURRENCY: Config<usize> = Config::new(
539 "persist_source_fetch_concurrency",
540 1,
541 "Maximum number of part fetches the persist source issues concurrently per worker \
542 (1 = serial).",
543 ParameterScope::Environment,
544);
545
546pub const USE_CRITICAL_SINCE_SNAPSHOT: Config<bool> = Config::new(
548 "persist_use_critical_since_snapshot",
549 false,
550 "Use the critical since (instead of the overall since) when taking snapshots in the controller or in fast-path peeks.",
551 ParameterScope::Environment,
552);
553
554pub const BATCH_BUILDER_MAX_OUTSTANDING_PARTS: Config<usize> = Config::new(
558 "persist_batch_builder_max_outstanding_parts",
559 2,
560 "The number of writes a batch builder can have outstanding before we slow down the writer.",
561 ParameterScope::Environment,
562);
563
564pub const COMPACTION_HEURISTIC_MIN_INPUTS: Config<usize> = Config::new(
568 "persist_compaction_heuristic_min_inputs",
569 8,
570 "Don't skip compaction if we have more than this many hollow batches as input.",
571 ParameterScope::Environment,
572);
573
574pub const COMPACTION_HEURISTIC_MIN_PARTS: Config<usize> = Config::new(
578 "persist_compaction_heuristic_min_parts",
579 8,
580 "Don't skip compaction if we have more than this many parts as input.",
581 ParameterScope::Environment,
582);
583
584pub const COMPACTION_HEURISTIC_MIN_UPDATES: Config<usize> = Config::new(
588 "persist_compaction_heuristic_min_updates",
589 1024,
590 "Don't skip compaction if we have more than this many updates as input.",
591 ParameterScope::Environment,
592);
593
594pub const COMPACTION_MEMORY_BOUND_BYTES: Config<usize> = Config::new(
599 "persist_compaction_memory_bound_bytes",
600 1024 * MiB,
601 "Attempt to limit compaction to this amount of memory.",
602 ParameterScope::Environment,
603);
604
605pub const GC_BLOB_DELETE_CONCURRENCY_LIMIT: Config<usize> = Config::new(
607 "persist_gc_blob_delete_concurrency_limit",
608 32,
609 "Limit the number of concurrent deletes GC can perform to this threshold.",
610 ParameterScope::Environment,
611);
612
613pub const STATE_VERSIONS_RECENT_LIVE_DIFFS_LIMIT: Config<usize> = Config::new(
623 "persist_state_versions_recent_live_diffs_limit",
624 30 * 128,
625 "Fetch this many diffs when fetching recent diffs.",
626 ParameterScope::Environment,
627);
628
629pub const USAGE_STATE_FETCH_CONCURRENCY_LIMIT: Config<usize> = Config::new(
631 "persist_usage_state_fetch_concurrency_limit",
632 8,
633 "Limit the concurrency in of fetching in the perioding Persist-storage-usage calculation.",
634 ParameterScope::Environment,
635);
636
637impl PostgresClientKnobs for PersistConfig {
638 fn connection_pool_max_size(&self) -> usize {
639 CONSENSUS_CONNECTION_POOL_MAX_SIZE.get(self)
640 }
641
642 fn connection_pool_max_wait(&self) -> Option<Duration> {
643 Some(CONSENSUS_CONNECTION_POOL_MAX_WAIT.get(self))
644 }
645
646 fn connection_pool_ttl(&self) -> Duration {
647 CONSENSUS_CONNECTION_POOL_TTL.get(self)
648 }
649
650 fn connection_pool_ttl_stagger(&self) -> Duration {
651 CONSENSUS_CONNECTION_POOL_TTL_STAGGER.get(self)
652 }
653
654 fn connect_timeout(&self) -> Duration {
655 CRDB_CONNECT_TIMEOUT.get(self)
656 }
657
658 fn tcp_user_timeout(&self) -> Duration {
659 CRDB_TCP_USER_TIMEOUT.get(self)
660 }
661
662 fn keepalives_idle(&self) -> Duration {
663 CRDB_KEEPALIVES_IDLE.get(self)
664 }
665
666 fn keepalives_interval(&self) -> Duration {
667 CRDB_KEEPALIVES_INTERVAL.get(self)
668 }
669
670 fn keepalives_retries(&self) -> u32 {
671 CRDB_KEEPALIVES_RETRIES.get(self)
672 }
673
674 fn statement_timeout(&self) -> Duration {
675 Duration::ZERO
677 }
678}
679
680#[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary, Serialize, Deserialize)]
681pub struct RetryParameters {
682 pub fixed_sleep: Duration,
683 pub initial_backoff: Duration,
684 pub multiplier: u32,
685 pub clamp: Duration,
686}
687
688impl RetryParameters {
689 pub fn persist_defaults() -> Self {
690 Self {
691 fixed_sleep: Duration::ZERO,
692 initial_backoff: Duration::from_millis(4),
695 multiplier: 2,
696 clamp: Duration::from_secs(16),
699 }
700 }
701
702 pub(crate) fn into_retry(self, now: SystemTime) -> Retry {
703 let seed = now
704 .duration_since(UNIX_EPOCH)
705 .map_or(0, |x| u64::from(x.subsec_nanos()));
706 Retry {
707 fixed_sleep: self.fixed_sleep,
708 initial_backoff: self.initial_backoff,
709 multiplier: self.multiplier,
710 clamp_backoff: self.clamp,
711 seed,
712 }
713 }
714}
715
716pub(crate) const BLOB_OPERATION_TIMEOUT: Config<Duration> = Config::new(
717 "persist_blob_operation_timeout",
718 Duration::from_secs(180),
719 "Maximum time allowed for a network call, including retry attempts.",
720 ParameterScope::Environment,
721);
722
723pub(crate) const BLOB_OPERATION_ATTEMPT_TIMEOUT: Config<Duration> = Config::new(
724 "persist_blob_operation_attempt_timeout",
725 Duration::from_secs(90),
726 "Maximum time allowed for a single network call.",
727 ParameterScope::Environment,
728);
729
730pub(crate) const BLOB_CONNECT_TIMEOUT: Config<Duration> = Config::new(
731 "persist_blob_connect_timeout",
732 Duration::from_secs(7),
733 "Maximum time to wait for a socket connection to be made.",
734 ParameterScope::Environment,
735);
736
737pub(crate) const BLOB_READ_TIMEOUT: Config<Duration> = Config::new(
738 "persist_blob_read_timeout",
739 Duration::from_secs(10),
740 "Maximum time to wait to read the first byte of a response, including connection time.",
741 ParameterScope::Environment,
742);
743
744impl BlobKnobs for PersistConfig {
745 fn operation_timeout(&self) -> Duration {
746 BLOB_OPERATION_TIMEOUT.get(self)
747 }
748
749 fn operation_attempt_timeout(&self) -> Duration {
750 BLOB_OPERATION_ATTEMPT_TIMEOUT.get(self)
751 }
752
753 fn connect_timeout(&self) -> Duration {
754 BLOB_CONNECT_TIMEOUT.get(self)
755 }
756
757 fn read_timeout(&self) -> Duration {
758 BLOB_READ_TIMEOUT.get(self)
759 }
760
761 fn is_cc_active(&self) -> bool {
762 self.is_cc_active
763 }
764}
765
766pub fn code_can_read_data(code_version: &Version, data_version: &Version) -> bool {
787 code_version.cmp_precedence(data_version).is_ge()
790}
791
792pub fn code_can_write_data(code_version: &Version, data_version: &Version) -> bool {
797 if !code_can_read_data(code_version, data_version) {
798 return false;
799 }
800
801 if code_version.major == 0 && code_version.minor <= SELF_MANAGED_VERSIONS[1].minor {
802 true
805 } else if code_version.major == 0 {
806 SELF_MANAGED_VERSIONS[0]
808 .cmp_precedence(data_version)
809 .is_le()
810 } else if code_version.major <= 26 {
811 SELF_MANAGED_VERSIONS[1]
813 .cmp_precedence(data_version)
814 .is_le()
815 } else {
816 code_version.major - 1 <= data_version.major
818 }
819}