feat(options): byte-rate IO limiter for compaction#2306
Open
shaunpatterson wants to merge 1 commit into
Open
Conversation
Add y.RateLimiter, a token-bucket byte-rate limiter, and wire it into compaction via Options.CompactionBytesPerSec (default 0 = unlimited = unchanged behavior, no limiter constructed). The limiter paces compaction (and value-log GC rewrite) IO so a compaction/GC storm cannot starve foreground reads. - y.RateLimiter: refill goroutine on a z.Closer adds ratePerSec*period tokens every 100ms (capped at burst = max(ratePerSec/10, oneBlock)), with fractional carry. Request(n) loop-drains the bucket so any n is satisfiable regardless of burst (no deadlock for n > burst). nil limiter is a no-op (disabled path, zero overhead). - Hook Request(len(key)+len(value)) after each builder.Add in subcompact. - L0 flush is NOT throttled (cannot induce a write stall). - v2 auto-tune (drain-ratio controller) documented in ratelimit.go, not implemented. - TDD: y/ratelimit_test.go (rate, burst-deadlock, close, concurrent) + ratelimit_integration_test.go (correctness under throttle, default-off). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NtGkC4K2J2XYwcAKwjhHbM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Badger's only compaction throttle is a concurrency semaphore (
y.Throttle) — there is no byte-rate control. A compaction (or value-log GC) storm can saturate disk IO and starve foreground reads, hurting tail latency.What changed
New opt-in
WithCompactionBytesPerSec(n)(default 0 = unlimited = current behavior). Whenn > 0, a token-buckety.RateLimiterpaces compaction output:Request(len(key)+len(value))is charged after eachbuilder.Addinsubcompact. L0 flush is deliberately not throttled, so throttling cannot induce a write stall.Compatibility & correctness
A nil limiter (the default,
n == 0) is a no-op with zero overhead — behavior unchanged. The limiter only paces IO; it never gates it, so compaction output/correctness is unaffected (verified).Requestloop-drains the bucket so any request larger than the burst is still satisfiable (no deadlock); the refill goroutine is stopped cleanly onClose.A drain-ratio auto-tuning controller is documented inline as a future v2; this PR ships the fixed-rate MVP.
Testing
go build,go vet, fullgo test . -count=1green;y.RateLimiterunit tests and a compaction integration test pass under-race(rate is enforced; large requests don't deadlock; no goroutine leak on close; data intact under throttling).🤖 Generated with Claude Code
https://claude.ai/code/session_01NtGkC4K2J2XYwcAKwjhHbM