From e850cc94b5c9609ef8473dc8994ff1bd281d0915 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Thu, 17 Jul 2025 07:14:11 +0000 Subject: [PATCH] demo that this solution creates too many leases --- pageserver/src/http/routes.rs | 30 +++++++++++++++++++++++-- test_runner/fixtures/pageserver/http.py | 11 +++++++++ test_runner/regress/test_hot_standby.py | 8 +++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pageserver/src/http/routes.rs b/pageserver/src/http/routes.rs index 2995a37089..8112831766 100644 --- a/pageserver/src/http/routes.rs +++ b/pageserver/src/http/routes.rs @@ -2181,8 +2181,29 @@ async fn handle_tenant_break( json_response(StatusCode::OK, ()) } +async fn get_lsn_leases_handler( + mut request: Request, + _cancel: CancellationToken, +) -> Result, ApiError> { + let tenant_shard_id: TenantShardId = parse_request_param(&request, "tenant_shard_id")?; + let timeline_id: TimelineId = parse_request_param(&request, "timeline_id")?; + check_permission(&request, Some(tenant_shard_id.tenant_id))?; + + let ctx = RequestContext::new(TaskKind::MgmtRequest, DownloadBehavior::Download); + + let state = get_state(&request); + + let timeline = + active_timeline_of_active_tenant(&state.tenant_manager, tenant_shard_id, timeline_id) + .await?; + + let leases = timeline.gc_info.read().unwrap().leases.clone(); + + json_response(StatusCode::OK, leases) +} + // Obtains an lsn lease on the given timeline. -async fn lsn_lease_handler( +async fn post_lsn_lease_handler( mut request: Request, _cancel: CancellationToken, ) -> Result, ApiError> { @@ -4002,9 +4023,14 @@ pub fn make_router( "/v1/tenant/:tenant_shard_id/timeline/:timeline_id/patch_index_part", |r| api_handler(r, timeline_patch_index_part_handler), ) + .get( + "/v1/tenant/:tenant_shard_id/timeline/:timeline_id/lsn_lease", + + |r| api_handler(r, get_lsn_leases_handler) + ) .post( "/v1/tenant/:tenant_shard_id/timeline/:timeline_id/lsn_lease", - |r| api_handler(r, lsn_lease_handler), + |r| api_handler(r, post_lsn_lease_handler), ) .put( "/v1/tenant/:tenant_shard_id/timeline/:timeline_id/do_gc", diff --git a/test_runner/fixtures/pageserver/http.py b/test_runner/fixtures/pageserver/http.py index d9037f2d08..15c76594a9 100644 --- a/test_runner/fixtures/pageserver/http.py +++ b/test_runner/fixtures/pageserver/http.py @@ -839,6 +839,17 @@ class PageserverHttpClient(requests.Session, MetricsGetter): res_json = res.json() return res_json + def timeline_lsn_lease_dump( + self, tenant_shard_id: TenantShardId, timeline_id: TimelineId + ): + res = self.get( + f"http://localhost:{self.port}/v1/tenant/{tenant_shard_id}/timeline/{timeline_id}/lsn_lease", + ) + self.verbose_error(res) + res_json = res.json() + return res_json + + def timeline_lsn_lease( self, tenant_id: TenantId | TenantShardId, timeline_id: TimelineId, lsn: Lsn ): diff --git a/test_runner/regress/test_hot_standby.py b/test_runner/regress/test_hot_standby.py index 552cb0a4d7..54bf89b0b2 100644 --- a/test_runner/regress/test_hot_standby.py +++ b/test_runner/regress/test_hot_standby.py @@ -200,6 +200,14 @@ def test_hot_standby_gc(neon_env_builder: NeonEnvBuilder, pause_apply: bool): res = s_cur.fetchone() assert res == (10000,) + for tenant_shard_id, pageserver in shards: + client = pageserver.http_client() + leases = client.timeline_lsn_lease_dump(tenant_shard_id, timeline_id) + leases_sorted = sorted(list(leases.items())) + log.info(f"lease state {tenant_shard_id=} {len(leases_sorted)} leases") + for lease in leases_sorted: + log.info(f"{lease=}") + assert len(leases) == 1 def run_pgbench(connstr: str, pg_bin: PgBin): log.info(f"Start a pgbench workload on pg {connstr}")