Merge 2025-04-09 main commit 'e7502a3d637932a59ee502ababb1df3d0e3bca26' into yuchen/direct-io-delta-image-layer-write

This commit is contained in:
Christian Schwarz
2025-04-11 16:18:48 +02:00
4 changed files with 44 additions and 7 deletions

View File

@@ -212,6 +212,12 @@ paths:
schema:
type: string
format: date-time
"412":
description: No timestamp is found for given LSN, e.g. if there had been no commits till LSN
content:
application/json:
schema:
$ref: "#/components/schemas/PreconditionFailedError"
/v1/tenant/{tenant_id}/timeline/{timeline_id}/get_lsn_by_timestamp:
parameters:

View File

@@ -989,7 +989,7 @@ async fn get_lsn_by_timestamp_handler(
if !tenant_shard_id.is_shard_zero() {
// Requires SLRU contents, which are only stored on shard zero
return Err(ApiError::BadRequest(anyhow!(
"Size calculations are only available on shard zero"
"Lsn calculations by timestamp are only available on shard zero"
)));
}
@@ -1064,7 +1064,7 @@ async fn get_timestamp_of_lsn_handler(
if !tenant_shard_id.is_shard_zero() {
// Requires SLRU contents, which are only stored on shard zero
return Err(ApiError::BadRequest(anyhow!(
"Size calculations are only available on shard zero"
"Timestamp calculations by lsn are only available on shard zero"
)));
}
@@ -1090,8 +1090,8 @@ async fn get_timestamp_of_lsn_handler(
.to_string();
json_response(StatusCode::OK, time)
}
None => Err(ApiError::NotFound(
anyhow::anyhow!("Timestamp for lsn {} not found", lsn).into(),
None => Err(ApiError::PreconditionFailed(
format!("Timestamp for lsn {} not found", lsn).into(),
)),
}
}

View File

@@ -691,7 +691,7 @@ impl Timeline {
Ok(buf.get_u32_le())
}
/// Get size of an SLRU segment
/// Does the slru segment exist?
pub(crate) async fn get_slru_segment_exists(
&self,
kind: SlruKind,
@@ -844,9 +844,9 @@ impl Timeline {
.await
}
/// Obtain the possible timestamp range for the given lsn.
/// Obtain the timestamp for the given lsn.
///
/// If the lsn has no timestamps, returns None. returns `(min, max, median)` if it has timestamps.
/// If the lsn has no timestamps (e.g. no commits), returns None.
pub(crate) async fn get_timestamp_for_lsn(
&self,
probe_lsn: Lsn,

View File

@@ -276,3 +276,34 @@ def test_ts_of_lsn_api(neon_env_builder: NeonEnvBuilder):
if i > 1:
before_timestamp = tbl[i - step_size][1]
assert timestamp >= before_timestamp, "before_timestamp before timestamp"
def test_timestamp_of_lsn_empty_branch(neon_env_builder: NeonEnvBuilder):
"""
Test that getting the timestamp of the head LSN of a newly created branch works.
This verifies that we don't get a 404 error when trying to get the timestamp
of the head LSN of a branch that was just created.
We now return a special status code 412 to indicate if there is no timestamp found for lsn.
Reproducer for https://github.com/neondatabase/neon/issues/11439
"""
env = neon_env_builder.init_start()
# Create a new branch
new_timeline_id = env.create_branch("test_timestamp_of_lsn_empty_branch")
# Retrieve the commit LSN of the empty branch, which we have never run postgres on
detail = env.pageserver.http_client().timeline_detail(
tenant_id=env.initial_tenant, timeline_id=new_timeline_id
)
head_lsn = detail["last_record_lsn"]
# Verify that we get 412 status code
with env.pageserver.http_client() as client:
with pytest.raises(PageserverApiException) as err:
client.timeline_get_timestamp_of_lsn(
env.initial_tenant,
new_timeline_id,
head_lsn,
)
assert err.value.status_code == 412