LCOV - differential code coverage report
Current view: top level - pageserver/src/consumption_metrics/metrics - tests.rs (source / functions) Coverage Total Hit CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 100.0 % 281 281 281
Current Date: 2023-10-19 02:04:12 Functions: 100.0 % 18 18 18
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  Line data    Source code
       1                 : use super::*;
       2                 : use std::collections::HashMap;
       3                 : use std::time::SystemTime;
       4                 : use utils::lsn::Lsn;
       5                 : 
       6 CBC           1 : #[test]
       7               1 : fn startup_collected_timeline_metrics_before_advancing() {
       8               1 :     let tenant_id = TenantId::generate();
       9               1 :     let timeline_id = TimelineId::generate();
      10               1 : 
      11               1 :     let mut metrics = Vec::new();
      12               1 :     let cache = HashMap::new();
      13               1 : 
      14               1 :     let initdb_lsn = Lsn(0x10000);
      15               1 :     let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
      16               1 : 
      17               1 :     let snap = TimelineSnapshot {
      18               1 :         loaded_at: (disk_consistent_lsn, SystemTime::now()),
      19               1 :         last_record_lsn: disk_consistent_lsn,
      20               1 :         current_exact_logical_size: Some(0x42000),
      21               1 :     };
      22               1 : 
      23               1 :     let now = DateTime::<Utc>::from(SystemTime::now());
      24               1 : 
      25               1 :     snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
      26               1 : 
      27               1 :     assert_eq!(
      28               1 :         metrics,
      29               1 :         &[
      30               1 :             MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
      31               1 :                 snap.loaded_at.1.into(),
      32               1 :                 now,
      33               1 :                 0
      34               1 :             ),
      35               1 :             MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
      36               1 :             MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
      37               1 :         ]
      38               1 :     );
      39               1 : }
      40                 : 
      41               1 : #[test]
      42               1 : fn startup_collected_timeline_metrics_second_round() {
      43               1 :     let tenant_id = TenantId::generate();
      44               1 :     let timeline_id = TimelineId::generate();
      45               1 : 
      46               1 :     let [now, before, init] = time_backwards();
      47               1 : 
      48               1 :     let now = DateTime::<Utc>::from(now);
      49               1 :     let before = DateTime::<Utc>::from(before);
      50               1 : 
      51               1 :     let initdb_lsn = Lsn(0x10000);
      52               1 :     let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
      53               1 : 
      54               1 :     let mut metrics = Vec::new();
      55               1 :     let cache = HashMap::from([
      56               1 :         MetricsKey::written_size(tenant_id, timeline_id).at(before, disk_consistent_lsn.0)
      57               1 :     ]);
      58               1 : 
      59               1 :     let snap = TimelineSnapshot {
      60               1 :         loaded_at: (disk_consistent_lsn, init),
      61               1 :         last_record_lsn: disk_consistent_lsn,
      62               1 :         current_exact_logical_size: Some(0x42000),
      63               1 :     };
      64               1 : 
      65               1 :     snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
      66               1 : 
      67               1 :     assert_eq!(
      68               1 :         metrics,
      69               1 :         &[
      70               1 :             MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0),
      71               1 :             MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
      72               1 :             MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
      73               1 :         ]
      74               1 :     );
      75               1 : }
      76                 : 
      77               1 : #[test]
      78               1 : fn startup_collected_timeline_metrics_nth_round_at_same_lsn() {
      79               1 :     let tenant_id = TenantId::generate();
      80               1 :     let timeline_id = TimelineId::generate();
      81               1 : 
      82               1 :     let [now, just_before, before, init] = time_backwards();
      83               1 : 
      84               1 :     let now = DateTime::<Utc>::from(now);
      85               1 :     let just_before = DateTime::<Utc>::from(just_before);
      86               1 :     let before = DateTime::<Utc>::from(before);
      87               1 : 
      88               1 :     let initdb_lsn = Lsn(0x10000);
      89               1 :     let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
      90               1 : 
      91               1 :     let mut metrics = Vec::new();
      92               1 :     let cache = HashMap::from([
      93               1 :         // at t=before was the last time the last_record_lsn changed
      94               1 :         MetricsKey::written_size(tenant_id, timeline_id).at(before, disk_consistent_lsn.0),
      95               1 :         // end time of this event is used for the next ones
      96               1 :         MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, just_before, 0),
      97               1 :     ]);
      98               1 : 
      99               1 :     let snap = TimelineSnapshot {
     100               1 :         loaded_at: (disk_consistent_lsn, init),
     101               1 :         last_record_lsn: disk_consistent_lsn,
     102               1 :         current_exact_logical_size: Some(0x42000),
     103               1 :     };
     104               1 : 
     105               1 :     snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
     106               1 : 
     107               1 :     assert_eq!(
     108               1 :         metrics,
     109               1 :         &[
     110               1 :             MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(just_before, now, 0),
     111               1 :             MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
     112               1 :             MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
     113               1 :         ]
     114               1 :     );
     115               1 : }
     116                 : 
     117               1 : #[test]
     118               1 : fn post_restart_written_sizes_with_rolled_back_last_record_lsn() {
     119               1 :     // it can happen that we lose the inmemorylayer but have previously sent metrics and we
     120               1 :     // should never go backwards
     121               1 : 
     122               1 :     let tenant_id = TenantId::generate();
     123               1 :     let timeline_id = TimelineId::generate();
     124               1 : 
     125               1 :     let [later, now, at_restart] = time_backwards();
     126               1 : 
     127               1 :     // FIXME: tests would be so much easier if we did not need to juggle back and forth
     128               1 :     // SystemTime and DateTime::<Utc> ... Could do the conversion only at upload time?
     129               1 :     let now = DateTime::<Utc>::from(now);
     130               1 :     let later = DateTime::<Utc>::from(later);
     131               1 :     let before_restart = at_restart - std::time::Duration::from_secs(5 * 60);
     132               1 :     let way_before = before_restart - std::time::Duration::from_secs(10 * 60);
     133               1 :     let before_restart = DateTime::<Utc>::from(before_restart);
     134               1 :     let way_before = DateTime::<Utc>::from(way_before);
     135               1 : 
     136               1 :     let snap = TimelineSnapshot {
     137               1 :         loaded_at: (Lsn(50), at_restart),
     138               1 :         last_record_lsn: Lsn(50),
     139               1 :         current_exact_logical_size: None,
     140               1 :     };
     141               1 : 
     142               1 :     let mut cache = HashMap::from([
     143               1 :         MetricsKey::written_size(tenant_id, timeline_id).at(before_restart, 100),
     144               1 :         MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
     145               1 :             way_before,
     146               1 :             before_restart,
     147               1 :             // not taken into account, but the timestamps are important
     148               1 :             999_999_999,
     149               1 :         ),
     150               1 :     ]);
     151               1 : 
     152               1 :     let mut metrics = Vec::new();
     153               1 :     snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
     154               1 : 
     155               1 :     assert_eq!(
     156               1 :         metrics,
     157               1 :         &[
     158               1 :             MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
     159               1 :                 before_restart,
     160               1 :                 now,
     161               1 :                 0
     162               1 :             ),
     163               1 :             MetricsKey::written_size(tenant_id, timeline_id).at(now, 100),
     164               1 :         ]
     165               1 :     );
     166                 : 
     167                 :     // now if we cache these metrics, and re-run while "still in recovery"
     168               1 :     cache.extend(metrics.drain(..));
     169               1 : 
     170               1 :     // "still in recovery", because our snapshot did not change
     171               1 :     snap.to_metrics(tenant_id, timeline_id, later, &mut metrics, &cache);
     172               1 : 
     173               1 :     assert_eq!(
     174               1 :         metrics,
     175               1 :         &[
     176               1 :             MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(now, later, 0),
     177               1 :             MetricsKey::written_size(tenant_id, timeline_id).at(later, 100),
     178               1 :         ]
     179               1 :     );
     180               1 : }
     181                 : 
     182               1 : #[test]
     183               1 : fn post_restart_current_exact_logical_size_uses_cached() {
     184               1 :     let tenant_id = TenantId::generate();
     185               1 :     let timeline_id = TimelineId::generate();
     186               1 : 
     187               1 :     let [now, at_restart] = time_backwards();
     188               1 : 
     189               1 :     let now = DateTime::<Utc>::from(now);
     190               1 :     let before_restart = at_restart - std::time::Duration::from_secs(5 * 60);
     191               1 :     let before_restart = DateTime::<Utc>::from(before_restart);
     192               1 : 
     193               1 :     let snap = TimelineSnapshot {
     194               1 :         loaded_at: (Lsn(50), at_restart),
     195               1 :         last_record_lsn: Lsn(50),
     196               1 :         current_exact_logical_size: None,
     197               1 :     };
     198               1 : 
     199               1 :     let cache = HashMap::from([
     200               1 :         MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(before_restart, 100)
     201               1 :     ]);
     202               1 : 
     203               1 :     let mut metrics = Vec::new();
     204               1 :     snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
     205               1 : 
     206               3 :     metrics.retain(|(key, _)| key.metric == Name::LogicalSize);
     207               1 : 
     208               1 :     assert_eq!(
     209               1 :         metrics,
     210               1 :         &[MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 100)]
     211               1 :     );
     212               1 : }
     213                 : 
     214               1 : #[test]
     215               1 : fn post_restart_synthetic_size_uses_cached_if_available() {
     216               1 :     let tenant_id = TenantId::generate();
     217               1 : 
     218               1 :     let ts = TenantSnapshot {
     219               1 :         resident_size: 1000,
     220               1 :         remote_size: 1000,
     221               1 :         // not yet calculated
     222               1 :         synthetic_size: 0,
     223               1 :     };
     224               1 : 
     225               1 :     let now = SystemTime::now();
     226               1 :     let before_restart = DateTime::<Utc>::from(now - std::time::Duration::from_secs(5 * 60));
     227               1 :     let now = DateTime::<Utc>::from(now);
     228               1 : 
     229               1 :     let cached = HashMap::from([MetricsKey::synthetic_size(tenant_id).at(before_restart, 1000)]);
     230               1 : 
     231               1 :     let mut metrics = Vec::new();
     232               1 :     ts.to_metrics(tenant_id, now, &cached, &mut metrics);
     233               1 : 
     234               1 :     assert_eq!(
     235               1 :         metrics,
     236               1 :         &[
     237               1 :             MetricsKey::remote_storage_size(tenant_id).at(now, 1000),
     238               1 :             MetricsKey::resident_size(tenant_id).at(now, 1000),
     239               1 :             MetricsKey::synthetic_size(tenant_id).at(now, 1000),
     240               1 :         ]
     241               1 :     );
     242               1 : }
     243                 : 
     244               1 : #[test]
     245               1 : fn post_restart_synthetic_size_is_not_sent_when_not_cached() {
     246               1 :     let tenant_id = TenantId::generate();
     247               1 : 
     248               1 :     let ts = TenantSnapshot {
     249               1 :         resident_size: 1000,
     250               1 :         remote_size: 1000,
     251               1 :         // not yet calculated
     252               1 :         synthetic_size: 0,
     253               1 :     };
     254               1 : 
     255               1 :     let now = SystemTime::now();
     256               1 :     let now = DateTime::<Utc>::from(now);
     257               1 : 
     258               1 :     let cached = HashMap::new();
     259               1 : 
     260               1 :     let mut metrics = Vec::new();
     261               1 :     ts.to_metrics(tenant_id, now, &cached, &mut metrics);
     262               1 : 
     263               1 :     assert_eq!(
     264               1 :         metrics,
     265               1 :         &[
     266               1 :             MetricsKey::remote_storage_size(tenant_id).at(now, 1000),
     267               1 :             MetricsKey::resident_size(tenant_id).at(now, 1000),
     268               1 :             // no synthetic size here
     269               1 :         ]
     270               1 :     );
     271               1 : }
     272                 : 
     273               4 : fn time_backwards<const N: usize>() -> [std::time::SystemTime; N] {
     274               4 :     let mut times = [std::time::SystemTime::UNIX_EPOCH; N];
     275               4 :     times[0] = std::time::SystemTime::now();
     276              12 :     for behind in 1..N {
     277               8 :         times[behind] = times[0] - std::time::Duration::from_secs(behind as u64);
     278               8 :     }
     279                 : 
     280               4 :     times
     281               4 : }
     282                 : 
     283               2 : pub(crate) const fn metric_examples(
     284               2 :     tenant_id: TenantId,
     285               2 :     timeline_id: TimelineId,
     286               2 :     now: DateTime<Utc>,
     287               2 :     before: DateTime<Utc>,
     288               2 : ) -> [RawMetric; 6] {
     289               2 :     [
     290               2 :         MetricsKey::written_size(tenant_id, timeline_id).at(now, 0),
     291               2 :         MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0),
     292               2 :         MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0),
     293               2 :         MetricsKey::remote_storage_size(tenant_id).at(now, 0),
     294               2 :         MetricsKey::resident_size(tenant_id).at(now, 0),
     295               2 :         MetricsKey::synthetic_size(tenant_id).at(now, 1),
     296               2 :     ]
     297               2 : }
        

Generated by: LCOV version 2.1-beta