mz_timestamp_oracle/config.rs
1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Unified configuration for timestamp oracles.
11//!
12//! This module provides a [`TimestampOracleConfig`] enum that holds the
13//! configuration for a timestamp oracle backend, allowing the choice of
14//! backend to be made at startup time.
15
16use std::sync::Arc;
17
18use mz_ore::metrics::MetricsRegistry;
19use mz_ore::now::NowFn;
20use mz_ore::url::SensitiveUrl;
21use mz_repr::Timestamp;
22
23use crate::TimestampOracle;
24use crate::metrics::Metrics;
25use crate::postgres_oracle::{
26 PostgresTimestampOracle, PostgresTimestampOracleConfig, TimestampOracleParameters,
27};
28
29/// Unified configuration for timestamp oracles.
30///
31/// This enum allows selecting between different timestamp oracle backends
32/// at startup time.
33#[derive(Clone, Debug)]
34pub enum TimestampOracleConfig {
35 /// Use a Postgres/CockroachDB-backed timestamp oracle.
36 Postgres(PostgresTimestampOracleConfig),
37}
38
39impl TimestampOracleConfig {
40 /// Create a timestamp oracle configuration from a URL.
41 ///
42 /// The backend is determined by the URL scheme:
43 /// - `postgres://` or `postgresql://` -> Postgres-backed oracle
44 ///
45 /// Returns an error if the URL scheme is not recognized.
46 pub fn from_url(
47 url: &SensitiveUrl,
48 metrics_registry: &MetricsRegistry,
49 ) -> Result<Self, anyhow::Error> {
50 let scheme = url.scheme();
51 match scheme {
52 "postgres" | "postgresql" => Ok(Self::new_postgres(url, metrics_registry)),
53 _ => {
54 anyhow::bail!(
55 "unsupported timestamp oracle URL scheme: '{}'. \
56 Supported schemes: postgres, postgresql",
57 scheme
58 )
59 }
60 }
61 }
62
63 /// Create a new Postgres-backed timestamp oracle configuration.
64 pub fn new_postgres(url: &SensitiveUrl, metrics_registry: &MetricsRegistry) -> Self {
65 TimestampOracleConfig::Postgres(PostgresTimestampOracleConfig::new(url, metrics_registry))
66 }
67
68 /// Returns the metrics for this configuration.
69 pub fn metrics(&self) -> Arc<Metrics> {
70 match self {
71 TimestampOracleConfig::Postgres(config) => Arc::clone(config.metrics()),
72 }
73 }
74
75 /// Opens a timestamp oracle for the given timeline.
76 pub async fn open(
77 &self,
78 timeline: String,
79 initially: Timestamp,
80 now_fn: NowFn,
81 read_only: bool,
82 ) -> Arc<dyn TimestampOracle<Timestamp> + Send + Sync> {
83 match self {
84 TimestampOracleConfig::Postgres(config) => Arc::new(
85 PostgresTimestampOracle::open(
86 config.clone(),
87 timeline,
88 initially,
89 now_fn,
90 read_only,
91 )
92 .await,
93 ),
94 }
95 }
96
97 /// Returns all known timelines and their current timestamps.
98 ///
99 /// This is used during initialization to restore timestamp state from the backend.
100 pub async fn get_all_timelines(&self) -> Result<Vec<(String, Timestamp)>, anyhow::Error> {
101 match self {
102 TimestampOracleConfig::Postgres(config) => {
103 PostgresTimestampOracle::<NowFn>::get_all_timelines(config.clone()).await
104 }
105 }
106 }
107
108 /// Applies configuration parameters.
109 ///
110 /// This is a no-op for non-Postgres backends.
111 pub fn apply_parameters(&self, params: TimestampOracleParameters) {
112 // Only the Postgres oracle supports parameters for now.
113 #[allow(irrefutable_let_patterns)]
114 if let TimestampOracleConfig::Postgres(pg_config) = self {
115 params.apply(pg_config)
116 }
117 }
118}