8000 feat(inkless:retention): shorten the file-cleaner interval to 2 minutes [KC-404] by jeqo · Pull Request #745 · aiven/inkless · GitHub
[go: up one dir, main page]

Skip to content

feat(inkless:retention): shorten the file-cleaner interval to 2 minutes [KC-404] - #745

Merged
jeqo merged 1 commit into
mainfrom
jeqo/file-cleaner-defaults
Aug 19, 2026
Merged

jeqo merged 1 commit into
mainfrom
jeqo/file-cleaner-defaults

Conversation

@jeqo
@jeqo jeqo commented Aug 11, 2026 •
Copy link
Copy Markdown
Contributor

A cycle used to fetch the whole deletion backlog, so running it less often was the only brake on query cost, and 5 minutes bought that brake. file.cleaner.max.files.per.cycle now bounds the fetch, which caps per-cycle cost and frees the interval to serve drain rate instead.

The old cadence has less headroom than it looks. Steady-state marking tracks file creation: a broker rotates a file every produce.commit.interval.ms (250 ms), or sooner when produce.buffer.max.bytes (8 MiB) fills. The timer sets a floor of 4 files/s per broker. Above roughly 32 MiB/s of ingest per broker the size trigger dominates at ingest / 8 MiB, about 12 files/s at 100 MiB/s.

Cluster drain is harder to pin down than a single cycle. The bounded query is deterministic and there is no leasing, so cycles that overlap on different brokers select the same rows and delete the same objects. Cluster drain therefore lands between 1x and Nx the cap per interval, and only the 1x end is safe to assume.

On that pessimistic assumption, 20000 files per 5 minutes drains 67 files/s. Six timer-bound brokers create 24 files/s, and six brokers at 100 MiB/s each create 75 files/s, so the old default goes underwater exactly when ingest is highest. 20000 files per 2 minutes drains 167 files/s.

Shortening the interval beats raising the cap for the same throughput. It holds the per-cycle burst at 20 DeleteObjects calls instead of 50, and S3 request-rate throttling responds to the burst. It also keeps the transient worklist smaller and shortens the jobs-pool connection hold time. A cycle holds that worklist about four times over, across the fetch, the key sets, and the confirmed-deleted set.

FileCleanerCycleSaturatedRate is the feedback signal. If it stays flat in production, the cap is over-provisioned and the interval can go back up.

Config changes

  • inkless.file.cleaner.interval.ms default: 300000 (5 minutes) -> 120000 (2 minutes). Clusters that pinned the old value keep it.
  • inkless.consume.batch.coordinate.cache.ttl.ms doc string: pointed at file.cleaner.interval.ms, which made the shorter interval look like it tightens the cache bound. SharedState.initialize enforces a ceiling of half of file.cleaner.retention.period.ms and rejects the broker config at startup otherwise. The retention period stays at 1 minute here, so the ceiling stays at 30 s and the interval change doesn't touch it. The doc string now names that config, and drops a duplicated word.

Operator impact

File-cleaner cycles run 2.5x more often, so per-cycle counters and rates re-baseline. Total deleted objects per unit of ingest doesn't change. Expect FileCleanerCycleSaturatedRate to drop wherever the cap was binding at the old cadence.

Testing

InklessConfigTest asserts the new default, and docs/inkless/configs.rst carries the new default and doc strings.

@jeqo
jeqo force-pushed the jeqo/file-cleaner-defaults branch from 263e4ad to 77a6b0f Compare August 12, 2026 13:25
@jeqo
jeqo requested a balanced review from Copilot August 12, 2026 13:26
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Shortens the Inkless file-cleaner cadence to improve deletion backlog drain rate.

Changes:

  • Changes the default interval from five to two minutes.
  • Updates configuration documentation and default-value test.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
InklessConfig.java Updates the default and configuration description.
InklessConfigTest.java Verifies the new default.
configs.rst Updates generated configuration documentation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/inkless/configs.rst Resolved
@jeqo
jeqo force-pushed the jeqo/file-cleaner-defaults branch 2 times, most recently from b46f302 to a45f288 Compare August 12, 2026 15:24
@jeqo
jeqo requested a balanced review from Copilot August 12, 2026 15:32
@jeqo jeqo changed the title feat(inkless:retention): shorten the file-cleaner interval to 2 minutes feat(inkless:retention): shorten the file-cleaner interval to 2 minutes [KC-404] Aug 12, 2026
@jeqo
jeqo marked this pull request as ready for review August 12, 2026 15:34
Base automatically changed from jeqo/file-cleaner-bound to main August 18, 2026 12:14
@jeqo
jeqo force-pushed the jeqo/file-cleaner-defaults branch from a45f288 to 303f94d Compare August 18, 2026 16:07
@jeqo
jeqo requested a balanced review from Copilot and removed request for Copilot August 18, 2026 16:14
Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

storage/inkless/src/main/java/io/aiven/inkless/config/InklessConfig.java:110

  • The PR rationale still treats this limit as half of file.cleaner.interval.ms, calculates a 60-second allowance, and calls the rule documentation-only. This corrected text matches SharedState.java:130-134: the broker enforces half of file.cleaner.retention.period.ms, so the unchanged one-minute default permits 30 seconds regardless of this PR's interval change. Update the PR body so the squashed commit doesn't preserve an incorrect safety argument.
        "The time to live must be <= half of the value of file.cleaner.retention.period.ms.";

A cycle used to fetch the whole deletion backlog, so running it less often
was the only brake on query cost, and 5 minutes bought that brake.
`file.cleaner.max.files.per.cycle` now bounds the fetch, which caps per-cycle
cost and frees the interval to serve drain rate instead.

The old cadence has less headroom than it looks. Steady-state marking tracks
file creation: a broker rotates a file every `produce.commit.interval.ms`
(250 ms), or sooner when `produce.buffer.max.bytes` (8 MiB) fills. The timer
sets a floor of 4 files/s per broker. Above roughly 32 MiB/s of ingest per
broker the size trigger dominates at ingest / 8 MiB, about 12 files/s at
100 MiB/s.

Cluster drain is harder to pin down than a single cycle. The bounded query is
deterministic and there is no leasing, so cycles that overlap on different
brokers select the same rows and delete the same objects. Cluster drain
therefore lands between 1x and Nx the cap per interval, and only the 1x end is
safe to assume.

On that pessimistic assumption, 20000 files per 5 minutes drains 67 files/s.
Six timer-bound brokers create 24 files/s, and six brokers at 100 MiB/s each
create 75 files/s, so the old default goes underwater exactly when ingest is
highest. 20000 files per 2 minutes drains 167 files/s.

Shortening the interval beats raising the cap for the same throughput. It holds
the per-cycle burst at 20 `DeleteObjects` calls instead of 50, and S3
request-rate throttling responds to the burst. It also keeps the transient
worklist smaller and shortens the jobs-pool connection hold time. A cycle holds
that worklist about four times over, across the fetch, the key sets, and the
confirmed-deleted set.

The `consume.batch.coordinate.cache.ttl.ms` documentation pointed the reader at
the wrong config, which made the shorter interval look like it tightens the
cache bound. `SharedState.initialize` enforces a ceiling of half of
`file.cleaner.retention.period.ms` and rejects the broker config at startup
otherwise. The retention period stays at 1 minute here, so the ceiling stays at
30 s and the interval change doesn't touch it. The doc string now names that
config.

`FileCleanerCycleSaturatedRate` is the feedback signal. If it stays flat in
production, the cap is over-provisioned and the interval can go back up.

Testing

`InklessConfigTest` asserts the new default, and `docs/inkless/configs.rst`
carries the new default and doc strings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jeqo
jeqo force-pushed the jeqo/file-cleaner-defaults branch from 303f94d to ef77801 Compare August 18, 2026 16:36
@jeqo
jeqo requested a review from tvainika August 18, 2026 19:11
@jeqo
jeqo merged commit 5e73d5d into main Aug 19, 2026
5 checks passed
@jeqo
jeqo deleted the jeqo/file-cleaner-defaults branch August 19, 2026 07:10
jeqo added a commit that referenced this pull request Aug 19, 2026
…es (#745)

A cycle used to fetch the whole deletion backlog, so running it less often
was the only brake on query cost, and 5 minutes bought that brake.
`file.cleaner.max.files.per.cycle` now bounds the fetch, which caps per-cycle
cost and frees the interval to serve drain rate instead.

The old cadence has less headroom than it looks. Steady-state marking tracks
file creation: a broker rotates a file every `produce.commit.interval.ms`
(250 ms), or sooner when `produce.buffer.max.bytes` (8 MiB) fills. The timer
sets a floor of 4 files/s per broker. Above roughly 32 MiB/s of ingest per
broker the size trigger dominates at ingest / 8 MiB, about 12 files/s at
100 MiB/s.

Cluster drain is harder to pin down than a single cycle. The bounded query is
deterministic and there is no leasing, so cycles that overlap on different
brokers select the same rows and delete the same objects. Cluster drain
therefore lands between 1x and Nx the cap per interval, and only the 1x end is
safe to assume.

On that pessimistic assumption, 20000 files per 5 minutes drains 67 files/s.
Six timer-bound brokers create 24 files/s, and six brokers at 100 MiB/s each
create 75 files/s, so the old default goes underwater exactly when ingest is
highest. 20000 files per 2 minutes drains 167 files/s.

Shortening the interval beats raising the cap for the same throughput. It holds
the per-cycle burst at 20 `DeleteObjects` calls instead of 50, and S3
request-rate throttling responds to the burst. It also keeps the transient
worklist smaller and shortens the jobs-pool connection hold time. A cycle holds
that worklist about four times over, across the fetch, the key sets, and the
confirmed-deleted set.

The `consume.batch.coordinate.cache.ttl.ms` documentation pointed the reader at
the wrong config, which made the shorter interval look like it tightens the
cache bound. `SharedState.initialize` enforces a ceiling of half of
`file.cleaner.retention.period.ms` and rejects the broker config at startup
otherwise. The retention period stays at 1 minute here, so the ceiling stays at
30 s and the interval change doesn't touch it. The doc string now names that
config.

`FileCleanerCycleSaturatedRate` is the feedback signal. If it stays flat in
production, the cap is over-provisioned and the interval can go back up.

Testing

`InklessConfigTest` asserts the new default, and `docs/inkless/configs.rst`
carries the new default and doc strings.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
jeqo added a commit that referenced this pull request Aug 19, 2026
…es (#745)

A cycle used to fetch the whole deletion backlog, so running it less often
was the only brake on query cost, and 5 minutes bought that brake.
`file.cleaner.max.files.per.cycle` now bounds the fetch, which caps per-cycle
cost and frees the interval to serve drain rate instead.

The old cadence has less headroom than it looks. Steady-state marking tracks
file creation: a broker rotates a file every `produce.commit.interval.ms`
(250 ms), or sooner when `produce.buffer.max.bytes` (8 MiB) fills. The timer
sets a floor of 4 files/s per broker. Above roughly 32 MiB/s of ingest per
broker the size trigger dominates at ingest / 8 MiB, about 12 files/s at
100 MiB/s.

Cluster drain is harder to pin down than a single cycle. The bounded query is
deterministic and there is no leasing, so cycles that overlap on different
brokers select the same rows and delete the same objects. Cluster drain
therefore lands between 1x and Nx the cap per interval, and only the 1x end is
safe to assume.

On that pessimistic assumption, 20000 files per 5 minutes drains 67 files/s.
Six timer-bound brokers create 24 files/s, and six brokers at 100 MiB/s each
create 75 files/s, so the old default goes underwater exactly when ingest is
highest. 20000 files per 2 minutes drains 167 files/s.

Shortening the interval beats raising the cap for the same throughput. It holds
the per-cycle burst at 20 `DeleteObjects` calls instead of 50, and S3
request-rate throttling responds to the burst. It also keeps the transient
worklist smaller and shortens the jobs-pool connection hold time. A cycle holds
that worklist about four times over, across the fetch, the key sets, and the
confirmed-deleted set.

The `consume.batch.coordinate.cache.ttl.ms` documentation pointed the reader at
the wrong config, which made the shorter interval look like it tightens the
cache bound. `SharedState.initialize` enforces a ceiling of half of
`file.cleaner.retention.period.ms` and rejects the broker config at startup
otherwise. The retention period stays at 1 minute here, so the ceiling stays at
30 s and the interval change doesn't touch it. The doc string now names that
config.

`FileCleanerCycleSaturatedRate` is the feedback signal. If it stays flat in
production, the cap is over-provisioned and the interval can go back up.

Testing

`InklessConfigTest` asserts the new default, and `docs/inkless/configs.rst`
carries the new default and doc strings.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
jeqo added a commit that referenced this pull request Aug 19, 2026
Covers inkless-release-0.46..inkless-release-0.47. Generated via the
inkless-changelog skill and curated:

- Metric deltas cross-checked against source commits (#716, #735, #743,
  #746, #715); all trace to real, shipped metrics, no documentation
  catch-up noise this increment.
- Postgres migration headers (V23-V26) checked for lock impact; V25 takes
  ACCESS EXCLUSIVE on files for a full-table scan at broker startup, V26
  offers a pre-upgrade CONCURRENTLY workaround.
- Added two config default changes the generator's diff-only detection
  missed (existing keys, not new ones): file.cleaner.interval.ms
  (5min -> 2min, #745) and retention.enforcement.interval.ms /
  max.batches.per.request (#744).
jeqo added a commit that referenced this pull request Sep 9, 2026
Covers inkless-release-0.46..inkless-release-0.47. Generated via the
inkless-changelog skill and curated:

- Metric deltas cross-checked against source commits (#716, #735, #743,
  #746, #715); all trace to real, shipped metrics, no documentation
  catch-up noise this increment.
- Postgres migration headers (V23-V26) checked for lock impact; V25 takes
  ACCESS EXCLUSIVE on files for a full-table scan at broker startup, V26
  offers a pre-upgrade CONCURRENTLY workaround.
- Added two config default changes the generator's diff-only detection
  missed (existing keys, not new ones): file.cleaner.interval.ms
  (5min -> 2min, #745) and retention.enforcement.interval.ms /
  max.batches.per.request (#744).
jeqo added a commit that referenced this pull request Sep 9, 2026
Covers inkless-release-0.46..inkless-release-0.47. Generated via the
inkless-changelog skill and curated:

- Metric deltas cross-checked against source commits (#716, #735, #743,
  #746, #715); all trace to real, shipped metrics, no documentation
  catch-up noise this increment.
- Postgres migration headers (V23-V26) checked for lock impact; V25 takes
  ACCESS EXCLUSIVE on files for a full-table scan at broker startup, V26
  offers a pre-upgrade CONCURRENTLY workaround.
- Added two config default changes the generator's diff-only detection
  missed (existing keys, not new ones): file.cleaner.interval.ms
  (5min -> 2min, #745) and retention.enforcement.interval.ms /
  max.batches.per.request (#744).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0