LCOV - code coverage report
Current view: top level - pageserver/src/tenant/secondary - heatmap.rs (source / functions) Coverage Total Hit
Test: 07bee600374ccd486c69370d0972d9035964fe68.info Lines: 31.5 % 54 17
Test Date: 2025-02-20 13:11:02 Functions: 6.5 % 31 2

            Line data    Source code
       1              : use std::{collections::HashMap, time::SystemTime};
       2              : 
       3              : use crate::tenant::{remote_timeline_client::index::LayerFileMetadata, storage_layer::LayerName};
       4              : 
       5              : use serde::{Deserialize, Serialize};
       6              : use serde_with::{serde_as, DisplayFromStr, TimestampSeconds};
       7              : 
       8              : use utils::{generation::Generation, id::TimelineId};
       9              : 
      10            0 : #[derive(Serialize, Deserialize)]
      11              : pub(crate) struct HeatMapTenant {
      12              :     /// Generation of the attached location that uploaded the heatmap: this is not required
      13              :     /// for correctness, but acts as a hint to secondary locations in order to detect thrashing
      14              :     /// in the unlikely event that two attached locations are both uploading conflicting heatmaps.
      15              :     pub(super) generation: Generation,
      16              : 
      17              :     pub(super) timelines: Vec<HeatMapTimeline>,
      18              : 
      19              :     /// Uploaders provide their own upload period in the heatmap, as a hint to downloaders
      20              :     /// of how frequently it is worthwhile to check for updates.
      21              :     ///
      22              :     /// This is optional for backward compat, and because we sometimes might upload
      23              :     /// a heatmap explicitly via API for a tenant that has no periodic upload configured.
      24              :     #[serde(default)]
      25              :     pub(super) upload_period_ms: Option<u128>,
      26              : }
      27              : 
      28              : impl HeatMapTenant {
      29            0 :     pub(crate) fn into_timelines_index(self) -> HashMap<TimelineId, HeatMapTimeline> {
      30            0 :         self.timelines
      31            0 :             .into_iter()
      32            0 :             .map(|htl| (htl.timeline_id, htl))
      33            0 :             .collect()
      34            0 :     }
      35              : }
      36              : 
      37              : #[serde_as]
      38            0 : #[derive(Serialize, Deserialize, Clone)]
      39              : pub(crate) struct HeatMapTimeline {
      40              :     #[serde_as(as = "DisplayFromStr")]
      41              :     pub(crate) timeline_id: TimelineId,
      42              : 
      43              :     pub(crate) layers: Vec<HeatMapLayer>,
      44              : }
      45              : 
      46              : #[serde_as]
      47            0 : #[derive(Serialize, Deserialize, Clone)]
      48              : pub(crate) struct HeatMapLayer {
      49              :     pub(crate) name: LayerName,
      50              :     pub(crate) metadata: LayerFileMetadata,
      51              : 
      52              :     #[serde_as(as = "TimestampSeconds<i64>")]
      53              :     pub(crate) access_time: SystemTime,
      54              :     // TODO: an actual 'heat' score that would let secondary locations prioritize downloading
      55              :     // the hottest layers, rather than trying to simply mirror whatever layers are on-disk on the primary.
      56              : }
      57              : 
      58              : impl HeatMapLayer {
      59          108 :     pub(crate) fn new(
      60          108 :         name: LayerName,
      61          108 :         metadata: LayerFileMetadata,
      62          108 :         access_time: SystemTime,
      63          108 :     ) -> Self {
      64          108 :         Self {
      65          108 :             name,
      66          108 :             metadata,
      67          108 :             access_time,
      68          108 :         }
      69          108 :     }
      70              : }
      71              : 
      72              : impl HeatMapTimeline {
      73           32 :     pub(crate) fn new(timeline_id: TimelineId, layers: Vec<HeatMapLayer>) -> Self {
      74           32 :         Self {
      75           32 :             timeline_id,
      76           32 :             layers,
      77           32 :         }
      78           32 :     }
      79              : }
      80              : 
      81              : pub(crate) struct HeatMapStats {
      82              :     pub(crate) bytes: u64,
      83              :     pub(crate) layers: usize,
      84              : }
      85              : 
      86              : impl HeatMapTenant {
      87            0 :     pub(crate) fn get_stats(&self) -> HeatMapStats {
      88            0 :         let mut stats = HeatMapStats {
      89            0 :             bytes: 0,
      90            0 :             layers: 0,
      91            0 :         };
      92            0 :         for timeline in &self.timelines {
      93            0 :             for layer in &timeline.layers {
      94            0 :                 stats.layers += 1;
      95            0 :                 stats.bytes += layer.metadata.file_size;
      96            0 :             }
      97              :         }
      98              : 
      99            0 :         stats
     100            0 :     }
     101              : 
     102            0 :     pub(crate) fn strip_atimes(self) -> Self {
     103            0 :         Self {
     104            0 :             timelines: self
     105            0 :                 .timelines
     106            0 :                 .into_iter()
     107            0 :                 .map(|mut tl| {
     108            0 :                     for layer in &mut tl.layers {
     109            0 :                         layer.access_time = SystemTime::UNIX_EPOCH;
     110            0 :                     }
     111            0 :                     tl
     112            0 :                 })
     113            0 :                 .collect(),
     114            0 :             generation: self.generation,
     115            0 :             upload_period_ms: self.upload_period_ms,
     116            0 :         }
     117            0 :     }
     118              : }
        

Generated by: LCOV version 2.1-beta