diff --git a/pageserver/src/tenant/timeline.rs b/pageserver/src/tenant/timeline.rs index cda873d649..3c0a300a9a 100644 --- a/pageserver/src/tenant/timeline.rs +++ b/pageserver/src/tenant/timeline.rs @@ -464,7 +464,6 @@ pub(crate) enum PageReconstructError { #[derive(Debug)] pub struct MissingKeyError { - stuck_at_lsn: bool, key: Key, shard: ShardNumber, cont_lsn: Lsn, @@ -476,23 +475,13 @@ pub struct MissingKeyError { impl std::fmt::Display for MissingKeyError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.stuck_at_lsn { - // Records are found in this timeline but no image layer or initial delta record was found. - write!( - f, - "could not find layer with more data for key {} (shard {:?}) at LSN {}, request LSN {}", - self.key, self.shard, self.cont_lsn, self.request_lsn - )?; - if let Some(ref ancestor_lsn) = self.ancestor_lsn { - write!(f, ", ancestor {}", ancestor_lsn)?; - } - } else { - // No records in this timeline. - write!( - f, - "could not find data for key {} (shard {:?}) at LSN {}, for request at LSN {}", - self.key, self.shard, self.cont_lsn, self.request_lsn - )?; + write!( + f, + "could not find data for key {} (shard {:?}) at LSN {}, request LSN {}", + self.key, self.shard, self.cont_lsn, self.request_lsn + )?; + if let Some(ref ancestor_lsn) = self.ancestor_lsn { + write!(f, ", ancestor {}", ancestor_lsn)?; } if !self.traversal_path.is_empty() { @@ -568,8 +557,8 @@ pub(crate) enum GetVectoredError { #[error("Requested at invalid LSN: {0}")] InvalidLsn(Lsn), - #[error("Requested key {0} not found")] - MissingKey(Key), + #[error("Requested key not found: {0}")] + MissingKey(MissingKeyError), #[error(transparent)] GetReadyAncestorError(GetReadyAncestorError), @@ -678,7 +667,7 @@ impl From for PageReconstructError { GetVectoredError::Cancelled => PageReconstructError::Cancelled, GetVectoredError::InvalidLsn(_) => PageReconstructError::Other(anyhow!("Invalid LSN")), err @ GetVectoredError::Oversized(_) => PageReconstructError::Other(err.into()), - err @ GetVectoredError::MissingKey(_) => PageReconstructError::Other(err.into()), + GetVectoredError::MissingKey(err) => PageReconstructError::MissingKey(err), GetVectoredError::GetReadyAncestorError(err) => PageReconstructError::from(err), GetVectoredError::Other(err) => PageReconstructError::Other(err), } @@ -1050,15 +1039,12 @@ impl Timeline { return Err(GetVectoredError::Cancelled) } // we only capture stuck_at_lsn=false now until we figure out https://github.com/neondatabase/neon/issues/7380 - Err(MissingKey(MissingKeyError { - stuck_at_lsn: false, - .. - })) if !NON_INHERITED_RANGE.contains(&key) => { + Err(MissingKey(err)) if !NON_INHERITED_RANGE.contains(&key) => { // The vectored read path handles non inherited keys specially. // If such a a key cannot be reconstructed from the current timeline, // the vectored read path returns a key level error as opposed to a top // level error. - return Err(GetVectoredError::MissingKey(key)); + return Err(GetVectoredError::MissingKey(err)); } Err(Other(err)) if err @@ -1154,7 +1140,7 @@ impl Timeline { match (lhs, rhs) { (Oversized(l), Oversized(r)) => l == r, (InvalidLsn(l), InvalidLsn(r)) => l == r, - (MissingKey(l), MissingKey(r)) => l == r, + (MissingKey(l), MissingKey(r)) => l.key == r.key, (GetReadyAncestorError(_), GetReadyAncestorError(_)) => true, (Other(_), Other(_)) => true, _ => false, @@ -3024,7 +3010,6 @@ impl Timeline { // Didn't make any progress in last iteration. Error out to avoid // getting stuck in the loop. return Err(PageReconstructError::MissingKey(MissingKeyError { - stuck_at_lsn: true, key, shard: self.shard_identity.get_shard_number(&key), cont_lsn: Lsn(cont_lsn.0 - 1), @@ -3039,7 +3024,6 @@ impl Timeline { } ValueReconstructResult::Missing => { return Err(PageReconstructError::MissingKey(MissingKeyError { - stuck_at_lsn: false, key, shard: self.shard_identity.get_shard_number(&key), cont_lsn, @@ -3215,7 +3199,6 @@ impl Timeline { reconstruct_state.on_key_error( key, PageReconstructError::MissingKey(MissingKeyError { - stuck_at_lsn: false, key, shard: self.shard_identity.get_shard_number(&key), cont_lsn, @@ -3248,7 +3231,17 @@ impl Timeline { } if keyspace.total_raw_size() != 0 { - return Err(GetVectoredError::MissingKey(keyspace.start().unwrap())); + return Err(GetVectoredError::MissingKey(MissingKeyError { + key: keyspace.start().unwrap(), /* better if we can store the full keyspace */ + shard: self + .shard_identity + .get_shard_number(&keyspace.start().unwrap()), + cont_lsn, + request_lsn, + ancestor_lsn: Some(timeline.ancestor_lsn), + traversal_path: vec![], + backtrace: None, + })); } Ok(()) diff --git a/test_runner/regress/test_lsn_mapping.py b/test_runner/regress/test_lsn_mapping.py index 37676ab0d4..5c99ca6733 100644 --- a/test_runner/regress/test_lsn_mapping.py +++ b/test_runner/regress/test_lsn_mapping.py @@ -110,10 +110,7 @@ def test_lsn_mapping(neon_env_builder: NeonEnvBuilder): # Test pageserver get_timestamp_of_lsn API def test_ts_of_lsn_api(neon_env_builder: NeonEnvBuilder): - if neon_env_builder.pageserver_get_impl == "vectored": - key_not_found_error = r".*Requested key.*not found,*" - else: - key_not_found_error = r".*could not find data for key.*" + key_not_found_error = r".*could not find data for key.*" env = neon_env_builder.init_start()