LCOV - code coverage report
Current view: top level - pageserver/src/consumption_metrics/metrics - tests.rs (source / functions) Coverage Total Hit
Test: 53437f7e869ac68c86c7d3e4c20964c0156f158c.info Lines: 100.0 % 274 274
Test Date: 2024-09-20 16:14:12 Functions: 100.0 % 12 12

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

Generated by: LCOV version 2.1-beta