From 75d0c8d6b9657e9bd8190ee52479617957da7a02 Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Wed, 5 Aug 2026 11:02:33 +0800 Subject: [PATCH] fix(quota): keep the degraded-baseline fallback off the write path's stack (#5728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fallback future embeds the whole snapshot loader, and every object write nests a quota check several futures deep, so inlining it grew each write's state machine by the loader's full size — the debug-build 2MiB worker-stack overflow class fixed for bucket-config writes in #5648. Box the fallback at its call site; the allocation only happens on the degraded path. --- crates/ecstore/src/bucket/quota/checker.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/ecstore/src/bucket/quota/checker.rs b/crates/ecstore/src/bucket/quota/checker.rs index 880dd7f7a..38b4e1423 100644 --- a/crates/ecstore/src/bucket/quota/checker.rs +++ b/crates/ecstore/src/bucket/quota/checker.rs @@ -214,7 +214,13 @@ impl QuotaChecker { // the writes issued before the next complete scanner cycle. Buckets // with no persisted baseline anywhere keep failing closed. let store = self.metadata_sys.read().await.object_store(); - if let Some(baseline) = crate::data_usage::lookup_degraded_bucket_usage_baseline(store, bucket).await { + // Box the fallback: it embeds the whole snapshot-load future, and every + // object write nests a quota check several futures deep, so keeping it + // inline would grow each write's state machine by the loader's full + // size — the debug-build 2MiB worker-stack overflow class fixed for + // bucket-config writes in #5648. The allocation only happens on the + // degraded path; the authoritative fast path returns above. + if let Some(baseline) = Box::pin(crate::data_usage::lookup_degraded_bucket_usage_baseline(store, bucket)).await { debug!(bucket, baseline, "Bucket quota admission using degraded persisted usage baseline"); return Ok(baseline); }