diff --git a/pageserver/src/consumption_metrics/metrics.rs b/pageserver/src/consumption_metrics/metrics.rs index acdf514101..698390f719 100644 --- a/pageserver/src/consumption_metrics/metrics.rs +++ b/pageserver/src/consumption_metrics/metrics.rs @@ -18,12 +18,25 @@ use crate::tenant::timeline::logical_size::CurrentLogicalSize; // management. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub(super) enum Name { - /// Timeline last_record_lsn, absolute + /// Timeline last_record_lsn, absolute. #[serde(rename = "written_size")] WrittenSize, /// Timeline last_record_lsn, incremental #[serde(rename = "written_data_bytes_delta")] WrittenSizeDelta, + /// Written bytes only on this timeline (not including ancestors): + /// written_size - ancestor_lsn + /// + /// On the root branch, this is equivalent to `written_size`. + #[serde(rename = "written_size_since_parent")] + WrittenSizeSinceParent, + /// PITR history size only on this timeline (not including ancestors): + /// last_record_lsn - max(pitr_cutoff, ancestor_lsn). + /// + /// On the root branch, this is its entire PITR history size. Not emitted if GC hasn't computed + /// the PITR cutoff yet. 0 if PITR is disabled. + #[serde(rename = "pitr_history_size_since_parent")] + PitrHistorySizeSinceParent, /// Timeline logical size #[serde(rename = "timeline_logical_size")] LogicalSize, @@ -157,6 +170,32 @@ impl MetricsKey { .incremental_values() } + /// `written_size` - `ancestor_lsn`. + const fn written_size_since_parent( + tenant_id: TenantId, + timeline_id: TimelineId, + ) -> AbsoluteValueFactory { + MetricsKey { + tenant_id, + timeline_id: Some(timeline_id), + metric: Name::WrittenSizeSinceParent, + } + .absolute_values() + } + + /// `written_size` - max(`pitr_cutoff`, `ancestor_lsn`). + const fn pitr_history_size_since_parent( + tenant_id: TenantId, + timeline_id: TimelineId, + ) -> AbsoluteValueFactory { + MetricsKey { + tenant_id, + timeline_id: Some(timeline_id), + metric: Name::PitrHistorySizeSinceParent, + } + .absolute_values() + } + /// Exact [`Timeline::get_current_logical_size`]. /// /// [`Timeline::get_current_logical_size`]: crate::tenant::Timeline::get_current_logical_size @@ -334,7 +373,13 @@ impl TenantSnapshot { struct TimelineSnapshot { loaded_at: (Lsn, SystemTime), last_record_lsn: Lsn, + ancestor_lsn: Lsn, current_exact_logical_size: Option, + /// Whether PITR is enabled (pitr_interval > 0). + pitr_enabled: bool, + /// The PITR cutoff LSN. None if not yet initialized. If PITR is disabled, this is approximately + /// Some(last_record_lsn), but may lag behind it since it's computed periodically. + pitr_cutoff: Option, } impl TimelineSnapshot { @@ -354,6 +399,9 @@ impl TimelineSnapshot { } else { let loaded_at = t.loaded_at; let last_record_lsn = t.get_last_record_lsn(); + let ancestor_lsn = t.get_ancestor_lsn(); + let pitr_enabled = !t.get_pitr_interval().is_zero(); + let pitr_cutoff = t.gc_info.read().unwrap().cutoffs.time; let current_exact_logical_size = { let span = tracing::info_span!("collect_metrics_iteration", tenant_id = %t.tenant_shard_id.tenant_id, timeline_id = %t.timeline_id); @@ -373,7 +421,10 @@ impl TimelineSnapshot { Ok(Some(TimelineSnapshot { loaded_at, last_record_lsn, + ancestor_lsn, current_exact_logical_size, + pitr_enabled, + pitr_cutoff, })) } } @@ -424,6 +475,8 @@ impl TimelineSnapshot { let up_to = now; + let written_size_last = written_size_now.value.max(prev.1); // don't regress + if let Some(delta) = written_size_now.value.checked_sub(prev.1) { let key_value = written_size_delta_key.from_until(prev.0, up_to, delta); // written_size_delta @@ -441,6 +494,27 @@ impl TimelineSnapshot { }); } + // Compute the branch-local written size. + let written_size_since_parent_key = + MetricsKey::written_size_since_parent(tenant_id, timeline_id); + metrics.push( + written_size_since_parent_key + .at(now, written_size_last.saturating_sub(self.ancestor_lsn.0)), + ); + + // Compute the branch-local PITR history size. Not emitted if GC hasn't yet computed the + // PITR cutoff. 0 if PITR is disabled. + let pitr_history_size_since_parent_key = + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id); + if !self.pitr_enabled { + metrics.push(pitr_history_size_since_parent_key.at(now, 0)); + } else if let Some(pitr_cutoff) = self.pitr_cutoff { + metrics.push(pitr_history_size_since_parent_key.at( + now, + written_size_last.saturating_sub(pitr_cutoff.max(self.ancestor_lsn).0), + )); + } + { let factory = MetricsKey::timeline_logical_size(tenant_id, timeline_id); let current_or_previous = self diff --git a/pageserver/src/consumption_metrics/metrics/tests.rs b/pageserver/src/consumption_metrics/metrics/tests.rs index 5cfb361e40..3379395b87 100644 --- a/pageserver/src/consumption_metrics/metrics/tests.rs +++ b/pageserver/src/consumption_metrics/metrics/tests.rs @@ -12,12 +12,17 @@ fn startup_collected_timeline_metrics_before_advancing() { let cache = HashMap::new(); let initdb_lsn = Lsn(0x10000); + let pitr_cutoff = Lsn(0x11000); let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2); + let logical_size = 0x42000; let snap = TimelineSnapshot { loaded_at: (disk_consistent_lsn, SystemTime::now()), last_record_lsn: disk_consistent_lsn, - current_exact_logical_size: Some(0x42000), + ancestor_lsn: Lsn(0), + current_exact_logical_size: Some(logical_size), + pitr_enabled: true, + pitr_cutoff: Some(pitr_cutoff), }; let now = DateTime::::from(SystemTime::now()); @@ -33,7 +38,11 @@ fn startup_collected_timeline_metrics_before_advancing() { 0 ), MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0), - MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000) + MetricsKey::written_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0 - pitr_cutoff.0), + MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, logical_size) ] ); } @@ -49,7 +58,9 @@ fn startup_collected_timeline_metrics_second_round() { let before = DateTime::::from(before); let initdb_lsn = Lsn(0x10000); + let pitr_cutoff = Lsn(0x11000); let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2); + let logical_size = 0x42000; let mut metrics = Vec::new(); let cache = HashMap::from([MetricsKey::written_size(tenant_id, timeline_id) @@ -59,7 +70,10 @@ fn startup_collected_timeline_metrics_second_round() { let snap = TimelineSnapshot { loaded_at: (disk_consistent_lsn, init), last_record_lsn: disk_consistent_lsn, - current_exact_logical_size: Some(0x42000), + ancestor_lsn: Lsn(0), + current_exact_logical_size: Some(logical_size), + pitr_enabled: true, + pitr_cutoff: Some(pitr_cutoff), }; snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); @@ -69,7 +83,11 @@ fn startup_collected_timeline_metrics_second_round() { &[ MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0), MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0), - MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000) + MetricsKey::written_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0 - pitr_cutoff.0), + MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, logical_size) ] ); } @@ -86,7 +104,9 @@ fn startup_collected_timeline_metrics_nth_round_at_same_lsn() { let before = DateTime::::from(before); let initdb_lsn = Lsn(0x10000); + let pitr_cutoff = Lsn(0x11000); let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2); + let logical_size = 0x42000; let mut metrics = Vec::new(); let cache = HashMap::from([ @@ -103,7 +123,10 @@ fn startup_collected_timeline_metrics_nth_round_at_same_lsn() { let snap = TimelineSnapshot { loaded_at: (disk_consistent_lsn, init), last_record_lsn: disk_consistent_lsn, - current_exact_logical_size: Some(0x42000), + ancestor_lsn: Lsn(0), + current_exact_logical_size: Some(logical_size), + pitr_enabled: true, + pitr_cutoff: Some(pitr_cutoff), }; snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); @@ -113,16 +136,18 @@ fn startup_collected_timeline_metrics_nth_round_at_same_lsn() { &[ MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(just_before, now, 0), MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0), - MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000) + MetricsKey::written_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0 - pitr_cutoff.0), + MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, logical_size) ] ); } +/// Tests that written sizes do not regress across restarts. #[test] fn post_restart_written_sizes_with_rolled_back_last_record_lsn() { - // it can happen that we lose the inmemorylayer but have previously sent metrics and we - // should never go backwards - let tenant_id = TenantId::generate(); let timeline_id = TimelineId::generate(); @@ -140,7 +165,10 @@ fn post_restart_written_sizes_with_rolled_back_last_record_lsn() { let snap = TimelineSnapshot { loaded_at: (Lsn(50), at_restart), last_record_lsn: Lsn(50), + ancestor_lsn: Lsn(0), current_exact_logical_size: None, + pitr_enabled: true, + pitr_cutoff: Some(Lsn(20)), }; let mut cache = HashMap::from([ @@ -169,6 +197,8 @@ fn post_restart_written_sizes_with_rolled_back_last_record_lsn() { 0 ), MetricsKey::written_size(tenant_id, timeline_id).at(now, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(now, 100), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(now, 80), ] ); @@ -183,6 +213,157 @@ fn post_restart_written_sizes_with_rolled_back_last_record_lsn() { &[ MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(now, later, 0), MetricsKey::written_size(tenant_id, timeline_id).at(later, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(later, 100), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(later, 80), + ] + ); +} + +/// Tests that written sizes do not regress across restarts, even on child branches. +#[test] +fn post_restart_written_sizes_with_rolled_back_last_record_lsn_and_ancestor_lsn() { + let tenant_id = TenantId::generate(); + let timeline_id = TimelineId::generate(); + + let [later, now, at_restart] = time_backwards(); + + // FIXME: tests would be so much easier if we did not need to juggle back and forth + // SystemTime and DateTime:: ... Could do the conversion only at upload time? + let now = DateTime::::from(now); + let later = DateTime::::from(later); + let before_restart = at_restart - std::time::Duration::from_secs(5 * 60); + let way_before = before_restart - std::time::Duration::from_secs(10 * 60); + let before_restart = DateTime::::from(before_restart); + let way_before = DateTime::::from(way_before); + + let snap = TimelineSnapshot { + loaded_at: (Lsn(50), at_restart), + last_record_lsn: Lsn(50), + ancestor_lsn: Lsn(40), + current_exact_logical_size: None, + pitr_enabled: true, + pitr_cutoff: Some(Lsn(20)), + }; + + let mut cache = HashMap::from([ + MetricsKey::written_size(tenant_id, timeline_id) + .at(before_restart, 100) + .to_kv_pair(), + MetricsKey::written_size_delta(tenant_id, timeline_id) + .from_until( + way_before, + before_restart, + // not taken into account, but the timestamps are important + 999_999_999, + ) + .to_kv_pair(), + ]); + + let mut metrics = Vec::new(); + snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until( + before_restart, + now, + 0 + ), + MetricsKey::written_size(tenant_id, timeline_id).at(now, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(now, 60), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(now, 60), + ] + ); + + // now if we cache these metrics, and re-run while "still in recovery" + cache.extend(metrics.drain(..).map(|x| x.to_kv_pair())); + + // "still in recovery", because our snapshot did not change + snap.to_metrics(tenant_id, timeline_id, later, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(now, later, 0), + MetricsKey::written_size(tenant_id, timeline_id).at(later, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(later, 60), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(later, 60), + ] + ); +} + +/// Tests that written sizes do not regress across restarts, even on child branches and +/// with a PITR cutoff after the branch point. +#[test] +fn post_restart_written_sizes_with_rolled_back_last_record_lsn_and_ancestor_lsn_and_pitr_cutoff() { + let tenant_id = TenantId::generate(); + let timeline_id = TimelineId::generate(); + + let [later, now, at_restart] = time_backwards(); + + // FIXME: tests would be so much easier if we did not need to juggle back and forth + // SystemTime and DateTime:: ... Could do the conversion only at upload time? + let now = DateTime::::from(now); + let later = DateTime::::from(later); + let before_restart = at_restart - std::time::Duration::from_secs(5 * 60); + let way_before = before_restart - std::time::Duration::from_secs(10 * 60); + let before_restart = DateTime::::from(before_restart); + let way_before = DateTime::::from(way_before); + + let snap = TimelineSnapshot { + loaded_at: (Lsn(50), at_restart), + last_record_lsn: Lsn(50), + ancestor_lsn: Lsn(30), + current_exact_logical_size: None, + pitr_enabled: true, + pitr_cutoff: Some(Lsn(40)), + }; + + let mut cache = HashMap::from([ + MetricsKey::written_size(tenant_id, timeline_id) + .at(before_restart, 100) + .to_kv_pair(), + MetricsKey::written_size_delta(tenant_id, timeline_id) + .from_until( + way_before, + before_restart, + // not taken into account, but the timestamps are important + 999_999_999, + ) + .to_kv_pair(), + ]); + + let mut metrics = Vec::new(); + snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until( + before_restart, + now, + 0 + ), + MetricsKey::written_size(tenant_id, timeline_id).at(now, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(now, 70), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(now, 60), + ] + ); + + // now if we cache these metrics, and re-run while "still in recovery" + cache.extend(metrics.drain(..).map(|x| x.to_kv_pair())); + + // "still in recovery", because our snapshot did not change + snap.to_metrics(tenant_id, timeline_id, later, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(now, later, 0), + MetricsKey::written_size(tenant_id, timeline_id).at(later, 100), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(later, 70), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(later, 60), ] ); } @@ -201,7 +382,10 @@ fn post_restart_current_exact_logical_size_uses_cached() { let snap = TimelineSnapshot { loaded_at: (Lsn(50), at_restart), last_record_lsn: Lsn(50), + ancestor_lsn: Lsn(0), current_exact_logical_size: None, + pitr_enabled: true, + pitr_cutoff: None, }; let cache = HashMap::from([MetricsKey::timeline_logical_size(tenant_id, timeline_id) @@ -286,16 +470,101 @@ fn time_backwards() -> [std::time::SystemTime; N] { times } +/// Tests that disabled PITR history does not yield any history size, even when the PITR cutoff +/// indicates otherwise. +#[test] +fn pitr_disabled_yields_no_history_size() { + let tenant_id = TenantId::generate(); + let timeline_id = TimelineId::generate(); + + let mut metrics = Vec::new(); + let cache = HashMap::new(); + + let initdb_lsn = Lsn(0x10000); + let pitr_cutoff = Lsn(0x11000); + let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2); + + let snap = TimelineSnapshot { + loaded_at: (disk_consistent_lsn, SystemTime::now()), + last_record_lsn: disk_consistent_lsn, + ancestor_lsn: Lsn(0), + current_exact_logical_size: None, + pitr_enabled: false, + pitr_cutoff: Some(pitr_cutoff), + }; + + let now = DateTime::::from(SystemTime::now()); + + snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until( + snap.loaded_at.1.into(), + now, + 0 + ), + MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0), + MetricsKey::written_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(now, 0), + ] + ); +} + +/// Tests that uninitialized PITR cutoff does not emit any history size metric at all. +#[test] +fn pitr_uninitialized_does_not_emit_history_size() { + let tenant_id = TenantId::generate(); + let timeline_id = TimelineId::generate(); + + let mut metrics = Vec::new(); + let cache = HashMap::new(); + + let initdb_lsn = Lsn(0x10000); + let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2); + + let snap = TimelineSnapshot { + loaded_at: (disk_consistent_lsn, SystemTime::now()), + last_record_lsn: disk_consistent_lsn, + ancestor_lsn: Lsn(0), + current_exact_logical_size: None, + pitr_enabled: true, + pitr_cutoff: None, + }; + + let now = DateTime::::from(SystemTime::now()); + + snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache); + + assert_eq!( + metrics, + &[ + MetricsKey::written_size_delta(tenant_id, timeline_id).from_until( + snap.loaded_at.1.into(), + now, + 0 + ), + MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0), + MetricsKey::written_size_since_parent(tenant_id, timeline_id) + .at(now, disk_consistent_lsn.0), + ] + ); +} + pub(crate) const fn metric_examples_old( tenant_id: TenantId, timeline_id: TimelineId, now: DateTime, before: DateTime, -) -> [RawMetric; 5] { +) -> [RawMetric; 7] { [ MetricsKey::written_size(tenant_id, timeline_id).at_old_format(now, 0), MetricsKey::written_size_delta(tenant_id, timeline_id) .from_until_old_format(before, now, 0), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at_old_format(now, 0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at_old_format(now, 0), MetricsKey::timeline_logical_size(tenant_id, timeline_id).at_old_format(now, 0), MetricsKey::remote_storage_size(tenant_id).at_old_format(now, 0), MetricsKey::synthetic_size(tenant_id).at_old_format(now, 1), @@ -307,10 +576,12 @@ pub(crate) const fn metric_examples( timeline_id: TimelineId, now: DateTime, before: DateTime, -) -> [NewRawMetric; 5] { +) -> [NewRawMetric; 7] { [ MetricsKey::written_size(tenant_id, timeline_id).at(now, 0), MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0), + MetricsKey::written_size_since_parent(tenant_id, timeline_id).at(now, 0), + MetricsKey::pitr_history_size_since_parent(tenant_id, timeline_id).at(now, 0), MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0), MetricsKey::remote_storage_size(tenant_id).at(now, 0), MetricsKey::synthetic_size(tenant_id).at(now, 1), diff --git a/pageserver/src/consumption_metrics/upload.rs b/pageserver/src/consumption_metrics/upload.rs index 19c5aec5b3..eba773272a 100644 --- a/pageserver/src/consumption_metrics/upload.rs +++ b/pageserver/src/consumption_metrics/upload.rs @@ -513,6 +513,14 @@ mod tests { line!(), r#"{"type":"incremental","start_time":"2023-09-14T00:00:00.123456789Z","stop_time":"2023-09-15T00:00:00.123456789Z","metric":"written_data_bytes_delta","idempotency_key":"2023-09-15 00:00:00.123456789 UTC-1-0000","value":0,"tenant_id":"00000000000000000000000000000000","timeline_id":"ffffffffffffffffffffffffffffffff"}"#, ), + ( + line!(), + r#"{"type":"absolute","time":"2023-09-15T00:00:00.123456789Z","metric":"written_size_since_parent","idempotency_key":"2023-09-15 00:00:00.123456789 UTC-1-0000","value":0,"tenant_id":"00000000000000000000000000000000","timeline_id":"ffffffffffffffffffffffffffffffff"}"#, + ), + ( + line!(), + r#"{"type":"absolute","time":"2023-09-15T00:00:00.123456789Z","metric":"pitr_history_size_since_parent","idempotency_key":"2023-09-15 00:00:00.123456789 UTC-1-0000","value":0,"tenant_id":"00000000000000000000000000000000","timeline_id":"ffffffffffffffffffffffffffffffff"}"#, + ), ( line!(), r#"{"type":"absolute","time":"2023-09-15T00:00:00.123456789Z","metric":"timeline_logical_size","idempotency_key":"2023-09-15 00:00:00.123456789 UTC-1-0000","value":0,"tenant_id":"00000000000000000000000000000000","timeline_id":"ffffffffffffffffffffffffffffffff"}"#, @@ -560,7 +568,7 @@ mod tests { assert_eq!(upgraded_samples, new_samples); } - fn metric_samples_old() -> [RawMetric; 5] { + fn metric_samples_old() -> [RawMetric; 7] { let tenant_id = TenantId::from_array([0; 16]); let timeline_id = TimelineId::from_array([0xff; 16]); @@ -572,7 +580,7 @@ mod tests { super::super::metrics::metric_examples_old(tenant_id, timeline_id, now, before) } - fn metric_samples() -> [NewRawMetric; 5] { + fn metric_samples() -> [NewRawMetric; 7] { let tenant_id = TenantId::from_array([0; 16]); let timeline_id = TimelineId::from_array([0xff; 16]); diff --git a/pageserver/src/tenant/timeline.rs b/pageserver/src/tenant/timeline.rs index eaaacd149c..72f7eebe28 100644 --- a/pageserver/src/tenant/timeline.rs +++ b/pageserver/src/tenant/timeline.rs @@ -2544,6 +2544,13 @@ impl Timeline { .unwrap_or(self.conf.default_tenant_conf.checkpoint_timeout) } + pub(crate) fn get_pitr_interval(&self) -> Duration { + let tenant_conf = &self.tenant_conf.load().tenant_conf; + tenant_conf + .pitr_interval + .unwrap_or(self.conf.default_tenant_conf.pitr_interval) + } + fn get_compaction_period(&self) -> Duration { let tenant_conf = self.tenant_conf.load().tenant_conf.clone(); tenant_conf diff --git a/test_runner/regress/test_pageserver_metric_collection.py b/test_runner/regress/test_pageserver_metric_collection.py index ffde08a73f..474258c9eb 100644 --- a/test_runner/regress/test_pageserver_metric_collection.py +++ b/test_runner/regress/test_pageserver_metric_collection.py @@ -508,6 +508,9 @@ PER_METRIC_VERIFIERS = { "remote_storage_size": CannotVerifyAnything, "written_size": WrittenDataVerifier, "written_data_bytes_delta": WrittenDataDeltaVerifier, + "written_size_since_parent": WrittenDataVerifier, # same as written_size on root + "pitr_cutoff": CannotVerifyAnything, + "pitr_history_size_since_parent": WrittenDataVerifier, # same as written_size on root w/o GC "timeline_logical_size": CannotVerifyAnything, "synthetic_storage_size": SyntheticSizeVerifier, }