diff --git a/libs/pageserver_api/src/models.rs b/libs/pageserver_api/src/models.rs index 71e32e479f..0f15fd79dc 100644 --- a/libs/pageserver_api/src/models.rs +++ b/libs/pageserver_api/src/models.rs @@ -515,6 +515,8 @@ pub enum HistoricLayerInfo { lsn_end: Lsn, remote: bool, access_stats: LayerAccessStats, + + remote_path: Option, }, Image { layer_file_name: String, @@ -523,6 +525,8 @@ pub enum HistoricLayerInfo { lsn_start: Lsn, remote: bool, access_stats: LayerAccessStats, + + remote_path: Option, }, } diff --git a/libs/remote_storage/src/lib.rs b/libs/remote_storage/src/lib.rs index e6d306ff66..2e5a20f928 100644 --- a/libs/remote_storage/src/lib.rs +++ b/libs/remote_storage/src/lib.rs @@ -81,6 +81,12 @@ impl std::fmt::Display for RemotePath { } } +impl From for String { + fn from(val: RemotePath) -> Self { + val.0.into() + } +} + impl RemotePath { pub fn new(relative_path: &Utf8Path) -> anyhow::Result { anyhow::ensure!( @@ -102,7 +108,7 @@ impl RemotePath { self.0.file_name() } - pub fn join(&self, segment: &Utf8Path) -> Self { + pub fn join>(&self, segment: P) -> Self { Self(self.0.join(segment)) } diff --git a/pageserver/src/deletion_queue.rs b/pageserver/src/deletion_queue.rs index 86be1b7094..7863c201fb 100644 --- a/pageserver/src/deletion_queue.rs +++ b/pageserver/src/deletion_queue.rs @@ -345,7 +345,7 @@ impl DeletionList { result.extend( timeline_layers .into_iter() - .map(|l| timeline_remote_path.join(&Utf8PathBuf::from(l))), + .map(|l| timeline_remote_path.join(Utf8PathBuf::from(l))), ); } } diff --git a/pageserver/src/tenant/storage_layer/layer.rs b/pageserver/src/tenant/storage_layer/layer.rs index f28f1c9444..18b15d54c0 100644 --- a/pageserver/src/tenant/storage_layer/layer.rs +++ b/pageserver/src/tenant/storage_layer/layer.rs @@ -3,6 +3,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use pageserver_api::models::{ HistoricLayerInfo, LayerAccessKind, LayerResidenceEventReason, LayerResidenceStatus, }; +use remote_storage::RemotePath; use std::ops::Range; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Weak}; @@ -305,6 +306,12 @@ impl Layer { &self.0.path } + /// This can return None even though it should return Some in some edge cases. + #[allow(unused)] + pub(crate) fn remote_path(&self) -> Option { + self.0.remote_path() + } + pub(crate) fn metadata(&self) -> LayerFileMetadata { self.0.metadata() } @@ -918,6 +925,17 @@ impl LayerInner { } } + /// This can return None even though it should return Some in some edge cases. + fn remote_path(&self) -> Option { + let tl = self.timeline.upgrade()?; // TODO: should distinguish this case, but, accuracy doesn't matter for this field. + Some(crate::tenant::remote_timeline_client::remote_layer_path( + &tl.tenant_id, + &tl.timeline_id, + &self.desc.filename(), + self.generation, + )) + } + fn info(&self, reset: LayerAccessStatsReset) -> HistoricLayerInfo { let layer_file_name = self.desc.filename().file_name(); @@ -937,6 +955,7 @@ impl LayerInner { lsn_end: lsn_range.end, remote, access_stats, + remote_path: self.remote_path().map(|p| p.into()), } } else { let lsn = self.desc.image_layer_lsn(); @@ -947,6 +966,7 @@ impl LayerInner { lsn_start: lsn, remote, access_stats, + remote_path: self.remote_path().map(|p| p.into()), } } } diff --git a/test_runner/fixtures/pageserver/http.py b/test_runner/fixtures/pageserver/http.py index 2f1d68b92c..724bfea8b8 100644 --- a/test_runner/fixtures/pageserver/http.py +++ b/test_runner/fixtures/pageserver/http.py @@ -58,6 +58,7 @@ class HistoricLayerInfo: lsn_start: str lsn_end: Optional[str] remote: bool + remote_path: Optional[str] = None @classmethod def from_json(cls, d: Dict[str, Any]) -> HistoricLayerInfo: @@ -68,6 +69,7 @@ class HistoricLayerInfo: lsn_start=d["lsn_start"], lsn_end=d.get("lsn_end"), remote=d["remote"], + remote_path=d.get("remote_path"), )