LCOV - code coverage report
Current view: top level - pageserver/src/tenant/storage_layer - layer_desc.rs (source / functions) Coverage Total Hit
Test: aca806cab4756d7eb6a304846130f4a73a5d5393.info Lines: 86.6 % 172 149
Test Date: 2025-04-24 20:31:15 Functions: 66.7 % 27 18

            Line data    Source code
       1              : use core::fmt::Display;
       2              : use std::ops::Range;
       3              : 
       4              : use pageserver_api::key::Key;
       5              : use pageserver_api::shard::TenantShardId;
       6              : use serde::{Deserialize, Serialize};
       7              : #[cfg(test)]
       8              : use utils::id::TenantId;
       9              : use utils::id::TimelineId;
      10              : use utils::lsn::Lsn;
      11              : 
      12              : use super::{DeltaLayerName, ImageLayerName, LayerName};
      13              : 
      14              : /// A unique identifier of a persistent layer.
      15              : ///
      16              : /// This is different from `LayerDescriptor`, which is only used in the benchmarks.
      17              : /// This struct contains all necessary information to find the image / delta layer. It also provides
      18              : /// a unified way to generate layer information like file name.
      19            0 : #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash)]
      20              : pub struct PersistentLayerDesc {
      21              :     pub tenant_shard_id: TenantShardId,
      22              :     pub timeline_id: TimelineId,
      23              :     /// Range of keys that this layer covers
      24              :     pub key_range: Range<Key>,
      25              :     /// Inclusive start, exclusive end of the LSN range that this layer holds.
      26              :     ///
      27              :     /// - For an open in-memory layer, the end bound is MAX_LSN
      28              :     /// - For a frozen in-memory layer or a delta layer, the end bound is a valid lsn after the
      29              :     ///   range start
      30              :     /// - An image layer represents snapshot at one LSN, so end_lsn is always the snapshot LSN + 1
      31              :     pub lsn_range: Range<Lsn>,
      32              :     /// Whether this is a delta layer, and also, is this incremental.
      33              :     pub is_delta: bool,
      34              :     pub file_size: u64,
      35              : }
      36              : 
      37              : /// A unique identifier of a persistent layer within the context of one timeline.
      38              : #[derive(Debug, PartialEq, Eq, Clone, Hash)]
      39              : pub struct PersistentLayerKey {
      40              :     pub key_range: Range<Key>,
      41              :     pub lsn_range: Range<Lsn>,
      42              :     pub is_delta: bool,
      43              : }
      44              : 
      45              : impl std::fmt::Display for PersistentLayerKey {
      46          348 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      47          348 :         write!(
      48          348 :             f,
      49          348 :             "{}..{} {}..{} is_delta={}",
      50          348 :             self.key_range.start,
      51          348 :             self.key_range.end,
      52          348 :             self.lsn_range.start,
      53          348 :             self.lsn_range.end,
      54          348 :             self.is_delta
      55          348 :         )
      56          348 :     }
      57              : }
      58              : 
      59              : impl From<ImageLayerName> for PersistentLayerKey {
      60            0 :     fn from(image_layer_name: ImageLayerName) -> Self {
      61            0 :         Self {
      62            0 :             key_range: image_layer_name.key_range,
      63            0 :             lsn_range: PersistentLayerDesc::image_layer_lsn_range(image_layer_name.lsn),
      64            0 :             is_delta: false,
      65            0 :         }
      66            0 :     }
      67              : }
      68              : 
      69              : impl From<DeltaLayerName> for PersistentLayerKey {
      70            0 :     fn from(delta_layer_name: DeltaLayerName) -> Self {
      71            0 :         Self {
      72            0 :             key_range: delta_layer_name.key_range,
      73            0 :             lsn_range: delta_layer_name.lsn_range,
      74            0 :             is_delta: true,
      75            0 :         }
      76            0 :     }
      77              : }
      78              : 
      79              : impl From<LayerName> for PersistentLayerKey {
      80            0 :     fn from(layer_name: LayerName) -> Self {
      81            0 :         match layer_name {
      82            0 :             LayerName::Image(i) => i.into(),
      83            0 :             LayerName::Delta(d) => d.into(),
      84              :         }
      85            0 :     }
      86              : }
      87              : impl PersistentLayerDesc {
      88      5114169 :     pub fn key(&self) -> PersistentLayerKey {
      89      5114169 :         PersistentLayerKey {
      90      5114169 :             key_range: self.key_range.clone(),
      91      5114169 :             lsn_range: self.lsn_range.clone(),
      92      5114169 :             is_delta: self.is_delta,
      93      5114169 :         }
      94      5114169 :     }
      95              : 
      96        13392 :     pub fn short_id(&self) -> impl Display {
      97        13392 :         self.layer_name()
      98        13392 :     }
      99              : 
     100              :     #[cfg(test)]
     101          264 :     pub fn new_test(key_range: Range<Key>, lsn_range: Range<Lsn>, is_delta: bool) -> Self {
     102          264 :         Self {
     103          264 :             tenant_shard_id: TenantShardId::unsharded(TenantId::generate()),
     104          264 :             timeline_id: TimelineId::generate(),
     105          264 :             key_range,
     106          264 :             lsn_range,
     107          264 :             is_delta,
     108          264 :             file_size: 0,
     109          264 :         }
     110          264 :     }
     111              : 
     112         2520 :     pub fn new_img(
     113         2520 :         tenant_shard_id: TenantShardId,
     114         2520 :         timeline_id: TimelineId,
     115         2520 :         key_range: Range<Key>,
     116         2520 :         lsn: Lsn,
     117         2520 :         file_size: u64,
     118         2520 :     ) -> Self {
     119         2520 :         Self {
     120         2520 :             tenant_shard_id,
     121         2520 :             timeline_id,
     122         2520 :             key_range,
     123         2520 :             lsn_range: Self::image_layer_lsn_range(lsn),
     124         2520 :             is_delta: false,
     125         2520 :             file_size,
     126         2520 :         }
     127         2520 :     }
     128              : 
     129         9624 :     pub fn new_delta(
     130         9624 :         tenant_shard_id: TenantShardId,
     131         9624 :         timeline_id: TimelineId,
     132         9624 :         key_range: Range<Key>,
     133         9624 :         lsn_range: Range<Lsn>,
     134         9624 :         file_size: u64,
     135         9624 :     ) -> Self {
     136         9624 :         Self {
     137         9624 :             tenant_shard_id,
     138         9624 :             timeline_id,
     139         9624 :             key_range,
     140         9624 :             lsn_range,
     141         9624 :             is_delta: true,
     142         9624 :             file_size,
     143         9624 :         }
     144         9624 :     }
     145              : 
     146          732 :     pub fn from_filename(
     147          732 :         tenant_shard_id: TenantShardId,
     148          732 :         timeline_id: TimelineId,
     149          732 :         filename: LayerName,
     150          732 :         file_size: u64,
     151          732 :     ) -> Self {
     152          732 :         match filename {
     153           24 :             LayerName::Image(i) => {
     154           24 :                 Self::new_img(tenant_shard_id, timeline_id, i.key_range, i.lsn, file_size)
     155              :             }
     156          708 :             LayerName::Delta(d) => Self::new_delta(
     157          708 :                 tenant_shard_id,
     158          708 :                 timeline_id,
     159          708 :                 d.key_range,
     160          708 :                 d.lsn_range,
     161          708 :                 file_size,
     162          708 :             ),
     163              :         }
     164          732 :     }
     165              : 
     166              :     /// Get the LSN that the image layer covers.
     167     15244428 :     pub fn image_layer_lsn(&self) -> Lsn {
     168     15244428 :         assert!(!self.is_delta);
     169     15244428 :         assert!(self.lsn_range.start + 1 == self.lsn_range.end);
     170     15244428 :         self.lsn_range.start
     171     15244428 :     }
     172              : 
     173              :     /// Get the LSN range corresponding to a single image layer LSN.
     174        14616 :     pub fn image_layer_lsn_range(lsn: Lsn) -> Range<Lsn> {
     175        14616 :         lsn..(lsn + 1)
     176        14616 :     }
     177              : 
     178              :     /// Get a delta layer name for this layer.
     179              :     ///
     180              :     /// Panic: if this is not a delta layer.
     181      7137460 :     pub fn delta_layer_name(&self) -> DeltaLayerName {
     182      7137460 :         assert!(self.is_delta);
     183      7137460 :         DeltaLayerName {
     184      7137460 :             key_range: self.key_range.clone(),
     185      7137460 :             lsn_range: self.lsn_range.clone(),
     186      7137460 :         }
     187      7137460 :     }
     188              : 
     189              :     /// Get a image layer name for this layer.
     190              :     ///
     191              :     /// Panic: if this is not an image layer, or the lsn range is invalid
     192        23380 :     pub fn image_layer_name(&self) -> ImageLayerName {
     193        23380 :         assert!(!self.is_delta);
     194        23380 :         assert!(self.lsn_range.start + 1 == self.lsn_range.end);
     195        23380 :         ImageLayerName {
     196        23380 :             key_range: self.key_range.clone(),
     197        23380 :             lsn: self.lsn_range.start,
     198        23380 :         }
     199        23380 :     }
     200              : 
     201      7160840 :     pub fn layer_name(&self) -> LayerName {
     202      7160840 :         if self.is_delta {
     203      7137460 :             self.delta_layer_name().into()
     204              :         } else {
     205        23380 :             self.image_layer_name().into()
     206              :         }
     207      7160840 :     }
     208              : 
     209              :     // TODO: remove this in the future once we refactor timeline APIs.
     210              : 
     211     38715728 :     pub fn get_lsn_range(&self) -> Range<Lsn> {
     212     38715728 :         self.lsn_range.clone()
     213     38715728 :     }
     214              : 
     215       569472 :     pub fn get_key_range(&self) -> Range<Key> {
     216       569472 :         self.key_range.clone()
     217       569472 :     }
     218              : 
     219            0 :     pub fn get_timeline_id(&self) -> TimelineId {
     220            0 :         self.timeline_id
     221            0 :     }
     222              : 
     223              :     /// Does this layer only contain some data for the key-range (incremental),
     224              :     /// or does it contain a version of every page? This is important to know
     225              :     /// for garbage collecting old layers: an incremental layer depends on
     226              :     /// the previous non-incremental layer.
     227        32820 :     pub fn is_incremental(&self) -> bool {
     228        32820 :         self.is_delta
     229        32820 :     }
     230              : 
     231     45755029 :     pub fn is_delta(&self) -> bool {
     232     45755029 :         self.is_delta
     233     45755029 :     }
     234              : 
     235           96 :     pub fn dump(&self) {
     236           96 :         if self.is_delta {
     237           84 :             println!(
     238           84 :                 "----- delta layer for ten {} tli {} keys {}-{} lsn {}-{} is_incremental {} size {} ----",
     239           84 :                 self.tenant_shard_id,
     240           84 :                 self.timeline_id,
     241           84 :                 self.key_range.start,
     242           84 :                 self.key_range.end,
     243           84 :                 self.lsn_range.start,
     244           84 :                 self.lsn_range.end,
     245           84 :                 self.is_incremental(),
     246           84 :                 self.file_size,
     247           84 :             );
     248           84 :         } else {
     249           12 :             println!(
     250           12 :                 "----- image layer for ten {} tli {} key {}-{} at {} is_incremental {} size {} ----",
     251           12 :                 self.tenant_shard_id,
     252           12 :                 self.timeline_id,
     253           12 :                 self.key_range.start,
     254           12 :                 self.key_range.end,
     255           12 :                 self.image_layer_lsn(),
     256           12 :                 self.is_incremental(),
     257           12 :                 self.file_size
     258           12 :             );
     259           12 :         }
     260           96 :     }
     261              : 
     262         1404 :     pub fn file_size(&self) -> u64 {
     263         1404 :         self.file_size
     264         1404 :     }
     265              : }
        

Generated by: LCOV version 2.1-beta