Skip to content

enhancement(file sink): batch writes per partition to reduce syscall … - #26081

Open
scMarkus wants to merge 1 commit into
vectordotdev:masterfrom
smartclip:file_sink
Open

enhancement(file sink): batch writes per partition to reduce syscall …#26081
scMarkus wants to merge 1 commit into
vectordotdev:masterfrom
smartclip:file_sink

Conversation

@scMarkus

Copy link
Copy Markdown
Contributor

…overhead

Events sharing the same rendered path are now accumulated into a single buffer and flushed with one write_all syscall per batch, rather than one syscall per event. This eliminates the O(events) syscall cost that caused throughput to degrade as partition count grew.

Adds a batch config block (max_bytes, timeout_secs) using the standard BatchConfig infrastructure. Defaults (10 MiB / 1 s) match other sinks.

Benchmark (10 000 events × 200 B, direct sink, no topology overhead):
single file: 124 K → 1.2 M elem/s (+875%)
4 partitions: 208 K → 494 K elem/s (+138%)
32 partitions: 60 K → 72 K elem/s (+20%)
64 partitions: 32 K → 36 K elem/s (+13%)

A follow-up could enable concurrent writes across partitions by lifting the file-handle map out of &mut self.

Closes: #20394

Summary

Vector configuration

How did you test this PR?

Is this a breaking change?

  • Yes
  • No

Does this PR include user facing changes?

  • Yes. Please add a changelog fragment based on our guidelines.
  • No. A maintainer will apply the no-changelog label to this PR.

References

Notes

  • Please read our Vector contributor resources.
  • Do not hesitate to use @vectordotdev/vector to reach out to us regarding this PR.
  • Some CI checks run only after we manually approve them.
    • We recommend adding a pre-push hook, please see this template.
    • Alternatively, we recommend running the following locally before pushing to the remote branch:
      • make fmt
      • make check-clippy (if there are failures it's possible some of them can be fixed with make clippy-fix)
      • make test
  • After a review is requested, please avoid force pushes to help us review incrementally.
    • Feel free to push as many commits as you want. They will be squashed into one before merging.
    • For example, you can run git merge origin master and git push.
  • If this PR introduces changes Vector dependencies (modifies Cargo.lock), please
    run make build-licenses to regenerate the license inventory and commit the changes (if any). More details on the dd-rust-license-tool.

…overhead

Events sharing the same rendered path are now accumulated into a single
buffer and flushed with one write_all syscall per batch, rather than one
syscall per event. This eliminates the O(events) syscall cost that caused
throughput to degrade as partition count grew.

Adds a `batch` config block (max_bytes, timeout_secs) using the standard
BatchConfig infrastructure. Defaults (10 MiB / 1 s) match other sinks.

Benchmark (10 000 events × 200 B, direct sink, no topology overhead):
  single file:  124 K → 1.2 M elem/s  (+875%)
  4 partitions: 208 K →  494 K elem/s  (+138%)
  32 partitions:  60 K →   72 K elem/s   (+20%)
  64 partitions:  32 K →   36 K elem/s   (+13%)

A follow-up could enable concurrent writes across partitions by lifting
the file-handle map out of &mut self.

Closes: vectordotdev#20394

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@scMarkus
scMarkus requested a review from a team as a code owner August 11, 2026 13:19
@github-actions github-actions Bot added the domain: sinks Anything related to the Vector's sinks label Aug 11, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aefa907a55

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/sinks/file/mod.rs

fn partition(&self, event: &Self::Item) -> Self::Key {
match self.path.render(event) {
Ok(bytes) => Some(bytes),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Confine rendered paths before filesystem work

With confinement enabled, this new partitioner returns the raw rendered path, so process_batch calls should_truncate/open_file before PathConfinement::confine has lexically rejected .. components. open_file runs create_dirs_nofollow before verify_parent, so an event field such as ../../../tmp/vector-escape/x in a /base/{{ field }}/out.log template can create /tmp/vector-escape outside base_dir before the batch is dropped. Preserve the old ordering by confining/normalizing the rendered path before any filesystem call.

Useful? React with 👍 / 👎.

Comment thread src/sinks/file/mod.rs
Comment on lines +445 to 448
// for event in events {
// event.metadata().update_status(EventStatus::Errored);
// }
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Mark failed opens as errored before returning

When open_file fails, for example due to permission denied while creating/opening the destination, this branch logs the batch as dropped and immediately returns with all event finalizers still at their default status. When those events are dropped the notifier records Dropped, which does not change the batch status, so sources with acknowledgements can receive a delivered ack for data that was never written; the confinement-error branch below has the same early return. Update every event's status to Errored before returning.

Useful? React with 👍 / 👎.

Comment thread src/sinks/file/mod.rs
Comment on lines +362 to +365
let mut batched =
input.batched_partitioned(partitioner, batch_settings.timeout, move |_| {
batch_settings.as_item_size_config(FileBatchSizer)
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve per-file order for oversized events

Using batched_partitioned here can reorder writes within one destination when a non-empty batch is followed by an event whose estimated size is at least batch.max_bytes: the partitioned batcher queues the previous batch, then immediately closes the oversized event's batch and drains closed batches with pop(), so the oversized record is yielded and written before earlier records for the same path. The file sink previously appended events in input order per file; flush closed batches FIFO or handle oversized items without reversing them.

Useful? React with 👍 / 👎.

Comment thread src/sinks/file/mod.rs
Comment on lines +362 to +365
let mut batched =
input.batched_partitioned(partitioner, batch_settings.timeout, move |_| {
batch_settings.as_item_size_config(FileBatchSizer)
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Honor batch timeout during steady traffic

The partitioned batcher used here resets an existing partition's expiration every time another event arrives for that path, so batch.timeout_secs is an inactivity timer rather than a maximum batch age. With the default 10 MB batch and a steady stream that stays below that size limit, a file can receive no writes for minutes or hours until traffic pauses or the batch fills, whereas this sink previously appended each event immediately and the new config describes a 1-second flush timeout.

Useful? React with 👍 / 👎.

@pront pront added the meta: awaiting author Pull requests that are awaiting their author. label Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: sinks Anything related to the Vector's sinks meta: awaiting author Pull requests that are awaiting their author.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add concurrent batching to the file sink

3 participants