Skip to content

fix: let executor spills use the work dir's free space by default - #2797

Merged
andygrove merged 3 commits into
apache:mainfrom
andygrove:fix-executor-spill-limit
Nov 10, 2026
Merged

andygrove merged 3 commits into
apache:mainfrom
andygrove:fix-executor-spill-limit

Conversation

@andygrove

@andygrove andygrove commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

Which issue does this PR close?

No single issue. Split out of #2792. Related: #2520 (performance review tracking).

Rationale for this change

DataFusion caps spill files at 100 GB per runtime. At TPC-H SF1000 on two executors, q5 and q18 spill more than that and fail, although the executor's work dir is on a 1 TB volume.

What changes are included in this PR?

When --max-temp-directory-size is not set, the executor uses the space available on the work dir's filesystem at startup (statvfs, unix only), never less than DataFusion's 100 GB default. If the free space cannot be read, a warning is logged and DataFusion's default applies as before. A configured value is used unchanged. A work dir that does not exist yet is measured on its closest existing parent. The default applies to every runtime the executor produces, including one from override_runtime_producer, as an explicit --max-temp-directory-size already does (the shipped executor binary always installs one).

Are there any user-facing changes?

Yes. With --max-temp-directory-size unset, the executor's spill limit is the work dir's free space at startup instead of 100 GB. The flag's help text is updated. The limit is per session runtime and measured once at startup, as the flag's limit is. Concurrent sessions can therefore together spill more than the free space, and shuffle files in the same dir are not counted. Set the flag where that matters, for example on a tmpfs or shared volume.

DataFusion caps spill files at 100 GB per runtime. At TPC-H SF1000 on
two executors, q5 and q18 spill more than that and fail, although the
executor's work dir is a 1 TB volume. When --max-temp-directory-size is
not set, use the space free on the work dir's filesystem at startup,
never less than DataFusion's default.
@andygrove
andygrove force-pushed the fix-executor-spill-limit branch from 2e84162 to d039b0e Compare November 7, 2026 17:04
@andygrove
andygrove marked this pull request as ready for review November 7, 2026 17:21

@villebro villebro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure of the runtime overhead implications, but by default, I feel it'd be better if we could check this limit from available work-dir space while the executor is running, instead of relying on a startup snapshot? As an operator, by default, I’d expect 1 TB free on the work-dir to allow workloads to spill beyond 100 GB when needed. With the current rule, a query can hit the 100 GB cap and fail despite that free space, which seems like unexpected default behavior.

Comment thread ballista/executor/src/config.rs Outdated
Comment on lines +229 to +231
/// that session's tasks). When unset, DataFusion's default (100 GB)
/// applies. Accepts the same values as `--memory-pool-size`.
/// that session's tasks). When unset, the space free on the work dir's
/// filesystem at startup, or DataFusion's default (100 GB) if that is
/// smaller. Accepts the same values as `--memory-pool-size`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This was slightly difficult to parse. Maybe we could reword this to something more readable, like

When unset, defaults to the smaller of the work-dir filesystem’s free space at startup and DataFusion’s 100 GB default.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good call, reworded. One small correction to the suggested text though: it's the larger of the two, not the smaller. The default never goes below DataFusion's 100 GB, so with 1 TB free the limit is about 1 TB.

@milenkovicm milenkovicm 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.

One comment regarding free space calculation


/// Bytes available to unprivileged users on the filesystem holding `path`, or
/// on the closest existing parent when `path` itself does not exist yet.
fn free_disk_space(path: &str) -> Option<u64> {

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.

We have sysinfo already as dependency, I believe it has free space, can we use it ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Switched to sysinfo::Disks, thanks! One wrinkle: on Linux sysinfo leaves tmpfs and network mounts out of its list by default. So I match the work dir to its disk by device id rather than path prefix. Otherwise a work dir on tmpfs would get the free space of /. If no listed disk matches, we fall back to DataFusion's default as before.

Replace the unsafe libc statvfs call with sysinfo's disk list, matching
the work dir to its disk by device id on unix, and reword the
--max-temp-directory-size docs to say the default is the larger of the
free space and DataFusion's 100 GB.
@andygrove

Copy link
Copy Markdown
Member Author

@villebro I think the old wording made this read backwards, sorry about that! With 1 TB free on the work dir at startup, the limit is about 1 TB, so the scenario you describe (failing at 100 GB despite the free space) is what this PR fixes. A live check is doable since DataFusion's DiskManager::set_max_temp_directory_size takes &self. But the executor would need to track every live session runtime and refresh them on a timer. The right value would also be "used + currently free", not just "currently free", or a query's own spills would shrink its limit under it. I'd rather keep this PR to the startup snapshot and do the live version as a follow-up, so I opened #2820 for it.

@milenkovicm milenkovicm 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.

thanks @andygrove

@andygrove
andygrove enabled auto-merge November 10, 2026 12:37
@andygrove
andygrove added this pull request to the merge queue Nov 10, 2026
Merged via the queue into apache:main with commit 3ba366d Nov 10, 2026
24 checks passed
@andygrove
andygrove deleted the fix-executor-spill-limit branch November 10, 2026 14:08
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