From 2c4bd592816ba31329086ea23bd28c9df0bb8d93 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 11 May 2026 21:39:45 -0700 Subject: [PATCH] feat(s3/lifecycle): plumb RetentionWindow into dailyrun.Config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Config.RetentionWindow field that runShard threads into engine.PromotedHash. Zero (the default) falls back to maxTTL, which matches Phase 4a behavior — PromotedHash stays empty and the partition-flip recovery trigger stays dormant. Pure plumbing. The handler still passes zero so nothing changes at runtime. The walker work (Phase 4b proper) sets a real retention from the meta-log boundary and the partition-flip trigger starts firing. --- weed/s3api/s3lifecycle/dailyrun/run.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/weed/s3api/s3lifecycle/dailyrun/run.go b/weed/s3api/s3lifecycle/dailyrun/run.go index b684d7fba..11badc600 100644 --- a/weed/s3api/s3lifecycle/dailyrun/run.go +++ b/weed/s3api/s3lifecycle/dailyrun/run.go @@ -40,6 +40,13 @@ type Config struct { // nil -> no rate limit. Shared across all shard goroutines. Limiter *rate.Limiter + // Meta-log retention boundary. Rules whose effective TTL exceeds + // this can't be serviced by replay alone and get partitioned into + // the walk view (engine.PromotedHash). 0 falls back to maxTTL, + // which keeps PromotedHash empty and the partition-flip recovery + // trigger dormant. + RetentionWindow time.Duration + ClientName string // 0 -> randomized per-run. ClientID int32 @@ -152,9 +159,16 @@ func runShard(ctx context.Context, cfg Config, snap *engine.Snapshot, runNow tim // one-time rewind to runNow - maxTTL, self-healing on save. rsh := engine.ReplayContentHash(snap) maxTTL := engine.MaxEffectiveTTL(snap) - // retentionWindow=maxTTL keeps promoted empty (no rule's TTL - // exceeds the max). Phase 4b plumbs real meta-log retention. - promoted := engine.PromotedHash(snap, maxTTL) + // Operator-supplied retention falls back to maxTTL, which forces + // promoted-empty (no rule's TTL can exceed the max). Once the + // walker handles walk-bound rules, the handler will pass the real + // meta-log retention here and PromotedHash starts catching + // partition flips. + retentionWindow := cfg.RetentionWindow + if retentionWindow <= 0 { + retentionWindow = maxTTL + } + promoted := engine.PromotedHash(snap, retentionWindow) if rsh == [32]byte{} { return cfg.Persister.Save(ctx, shardID, Cursor{