mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
test(s3/lifecycle/engine): pin delay-group dedup across buckets (#9418)
Compile a 100-bucket × 5-rule snapshot where the five Days values include duplicates (1, 1, 7, 7, 30) and assert: - snap.actions has 500 entries — every (bucket, rule) compiles to its own ActionKey, no collapse. - snap.originalDelayGroups has exactly 3 entries — the routing index is keyed by Delay, so same-day rules across all buckets share a group. This is the property that lets the dispatcher index by delay group rather than per-rule. - Per-group key count = (rules with that day) × buckets, so every action is reachable from its group entry.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -322,3 +323,60 @@ func TestEngine_SnapshotAtomicSwap(t *testing.T) {
|
||||
t.Fatalf("Engine.Snapshot should return the latest")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompile_DelayGroupsDedupeAcrossBuckets pins the scaling property
|
||||
// the dispatcher relies on: originalDelayGroups is keyed by Delay, so N
|
||||
// rules sharing the same Days threshold across M buckets collapse into
|
||||
// one delay group with N*M action keys — not N*M groups. The dispatch
|
||||
// path can then index by delay group rather than per-rule.
|
||||
func TestCompile_DelayGroupsDedupeAcrossBuckets(t *testing.T) {
|
||||
const buckets = 100
|
||||
const rulesPerBucket = 5
|
||||
// Five rules per bucket, but only three distinct day values, so two
|
||||
// pairs of rules per bucket share a delay group.
|
||||
dayValues := []int{1, 1, 7, 7, 30}
|
||||
distinctDays := map[int]bool{}
|
||||
for _, d := range dayValues {
|
||||
distinctDays[d] = true
|
||||
}
|
||||
|
||||
inputs := make([]CompileInput, buckets)
|
||||
prior := map[s3lifecycle.ActionKey]PriorState{}
|
||||
for b := 0; b < buckets; b++ {
|
||||
bucket := "b" + strconv.Itoa(b)
|
||||
rules := make([]*s3lifecycle.Rule, rulesPerBucket)
|
||||
for r, days := range dayValues {
|
||||
rule := ruleExpDays("r"+strconv.Itoa(r), "p"+strconv.Itoa(r)+"/", days)
|
||||
rules[r] = rule
|
||||
prior[s3lifecycle.ActionKey{
|
||||
Bucket: bucket,
|
||||
RuleHash: s3lifecycle.RuleHash(rule),
|
||||
ActionKind: s3lifecycle.ActionKindExpirationDays,
|
||||
}] = PriorState{BootstrapComplete: true}
|
||||
}
|
||||
inputs[b] = CompileInput{Bucket: bucket, Rules: rules}
|
||||
}
|
||||
|
||||
e := New()
|
||||
snap := e.Compile(inputs, CompileOptions{PriorStates: prior})
|
||||
|
||||
if got := len(snap.actions); got != buckets*rulesPerBucket {
|
||||
t.Fatalf("want %d actions (no collapse), got %d", buckets*rulesPerBucket, got)
|
||||
}
|
||||
if got := len(snap.originalDelayGroups); got != len(distinctDays) {
|
||||
t.Fatalf("want %d delay groups (one per distinct Days), got %d",
|
||||
len(distinctDays), got)
|
||||
}
|
||||
// Per-group key count: each distinct day appears in `count` rules per
|
||||
// bucket, so the group holds count*buckets keys.
|
||||
wantPerGroup := map[time.Duration]int{}
|
||||
for _, d := range dayValues {
|
||||
wantPerGroup[s3lifecycle.DaysToDuration(d)] += buckets
|
||||
}
|
||||
for delay, want := range wantPerGroup {
|
||||
if got := len(snap.originalDelayGroups[delay]); got != want {
|
||||
t.Fatalf("delay %v: want %d action keys, got %d", delay, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user