From 79f5139f0afe08eee7122bf8fa067c15ad1764e2 Mon Sep 17 00:00:00 2001 From: Alex Chi Z Date: Wed, 9 Jul 2025 16:12:02 -0400 Subject: [PATCH] test: force GC API skips precondition checks Signed-off-by: Alex Chi Z --- pageserver/src/http/routes.rs | 12 +++++++++++- pageserver/src/tenant.rs | 16 ++++++++++++++-- pageserver/src/tenant/mgr.rs | 10 +++++++++- test_runner/fixtures/pageserver/http.py | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/pageserver/src/http/routes.rs b/pageserver/src/http/routes.rs index 3612686b5d..c6cc978679 100644 --- a/pageserver/src/http/routes.rs +++ b/pageserver/src/http/routes.rs @@ -2221,6 +2221,9 @@ async fn timeline_gc_handler( ) -> Result, ApiError> { let tenant_shard_id: TenantShardId = parse_request_param(&request, "tenant_shard_id")?; let timeline_id: TimelineId = parse_request_param(&request, "timeline_id")?; + let skip_precond_checks = + parse_query_param::<_, bool>(&request, "skip_precond_checks")?.unwrap_or(false); + check_permission(&request, Some(tenant_shard_id.tenant_id))?; let gc_req: TimelineGcRequest = json_request(&mut request).await?; @@ -2230,7 +2233,14 @@ async fn timeline_gc_handler( let ctx = RequestContext::new(TaskKind::MgmtRequest, DownloadBehavior::Download); let gc_result = state .tenant_manager - .immediate_gc(tenant_shard_id, timeline_id, gc_req, cancel, &ctx) + .immediate_gc( + tenant_shard_id, + timeline_id, + gc_req, + cancel, + &ctx, + skip_precond_checks, + ) .await?; json_response(StatusCode::OK, gc_result) diff --git a/pageserver/src/tenant.rs b/pageserver/src/tenant.rs index f576119db8..59d612a137 100644 --- a/pageserver/src/tenant.rs +++ b/pageserver/src/tenant.rs @@ -3075,7 +3075,6 @@ impl TenantShard { /// `pitr` specifies the same as a time difference from the current time. The effective /// GC cutoff point is determined conservatively by either `horizon` and `pitr`, whichever /// requires more history to be retained. - // pub(crate) async fn gc_iteration( &self, target_timeline_id: Option, @@ -3083,6 +3082,19 @@ impl TenantShard { pitr: Duration, cancel: &CancellationToken, ctx: &RequestContext, + ) -> Result { + self.gc_iteration_inner(target_timeline_id, horizon, pitr, cancel, ctx, false) + .await + } + + pub(crate) async fn gc_iteration_inner( + &self, + target_timeline_id: Option, + horizon: u64, + pitr: Duration, + cancel: &CancellationToken, + ctx: &RequestContext, + skip_precond_checks: bool, ) -> Result { // Don't start doing work during shutdown if let TenantState::Stopping { .. } = self.current_state() { @@ -3094,7 +3106,7 @@ impl TenantShard { return Err(GcError::NotActive); } - { + if !skip_precond_checks { let conf = self.tenant_conf.load(); // If we may not delete layers, then simply skip GC. Even though a tenant diff --git a/pageserver/src/tenant/mgr.rs b/pageserver/src/tenant/mgr.rs index 15853d3614..66443f13f2 100644 --- a/pageserver/src/tenant/mgr.rs +++ b/pageserver/src/tenant/mgr.rs @@ -2357,6 +2357,7 @@ impl TenantManager { gc_req: TimelineGcRequest, cancel: CancellationToken, ctx: &RequestContext, + skip_precond_checks: bool, ) -> Result { let tenant = { let guard = self.tenants.read().unwrap(); @@ -2383,7 +2384,14 @@ impl TenantManager { #[allow(unused_mut)] let mut result = tenant - .gc_iteration(Some(timeline_id), gc_horizon, pitr, &cancel, &ctx) + .gc_iteration_inner( + Some(timeline_id), + gc_horizon, + pitr, + &cancel, + &ctx, + skip_precond_checks, + ) .await; // FIXME: `gc_iteration` can return an error for multiple reasons; we should handle it // better once the types support it. diff --git a/test_runner/fixtures/pageserver/http.py b/test_runner/fixtures/pageserver/http.py index 79cfba8da6..57480fa246 100644 --- a/test_runner/fixtures/pageserver/http.py +++ b/test_runner/fixtures/pageserver/http.py @@ -695,6 +695,7 @@ class PageserverHttpClient(requests.Session, MetricsGetter): tenant_id: TenantId | TenantShardId, timeline_id: TimelineId, gc_horizon: int | None, + skip_precond_checks: bool = True, ) -> dict[str, Any]: """ Unlike most handlers, this will wait for the layers to be actually @@ -708,6 +709,7 @@ class PageserverHttpClient(requests.Session, MetricsGetter): res = self.put( f"http://localhost:{self.port}/v1/tenant/{tenant_id}/timeline/{timeline_id}/do_gc", json={"gc_horizon": gc_horizon}, + params={"skip_precond_checks": skip_precond_checks}, ) log.info(f"Got GC request response code: {res.status_code}") self.verbose_error(res)