feat: Add sort-based shuffle implementation - #81
Open
andygrove wants to merge 18 commits into
Open
Conversation
This adds an alternative shuffle implementation that writes a single consolidated file per input partition (sorted by output partition ID) along with an index file, similar to Apache Spark's sort-based shuffle. This approach reduces file count from N × M (N input partitions × M output partitions) to 2 × N files (one data + one index file per input partition). Key components: - SortShuffleWriterExec: ExecutionPlan implementation - PartitionBuffer: In-memory buffering per partition - SpillManager: Spill-to-disk when memory pressure is high - ShuffleIndex: Index file I/O (little-endian i64 offsets) - SortShuffleConfig: Configuration (buffer size, memory limit, spill threshold) New configuration options: - ballista.shuffle.sort_based.enabled (default: false) - ballista.shuffle.sort_based.buffer_size (default: 1MB) - ballista.shuffle.sort_based.memory_limit (default: 256MB) - ballista.shuffle.sort_based.spill_threshold (default: 0.8) This implementation is inspired by Apache DataFusion Comet's shuffle writer: https://github.com/apache/datafusion-comet/blob/main/native/core/src/execution/shuffle/shuffle_writer.rs Work remaining: - Update DistributedPlanner to use SortShuffleWriterExec when enabled - Update ShuffleReaderExec to detect and read sort shuffle format - Add protobuf serialization for the new execution plan - End-to-end integration tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit integrates the sort-based shuffle writer with the distributed planner and execution graph: - Add ShuffleWriter trait to provide a common interface for both ShuffleWriterExec and SortShuffleWriterExec - Update DistributedPlanner to return Vec<Arc<dyn ShuffleWriter>> - Update ExecutionStageBuilder to work with ShuffleWriter trait - Add protobuf serialization for SortShuffleWriterExec - Update execution_graph, execution_stage, and diagram modules The planner will now create SortShuffleWriterExec when: - ballista.shuffle.sort_based.enabled is true - The partitioning is Hash partitioning Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…chmarks - Update fetch_partition_local to detect sort-based shuffle format by checking for the presence of an index file - When sort shuffle is detected, read partition data using the index file to locate the correct byte range - Add shuffle_bench binary for comparing hash vs sort shuffle performance - Configurable number of rows, partitions, batch size - Reports timing, file count, and throughput metrics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update DefaultExecutionEngine to handle both ShuffleWriterExec and SortShuffleWriterExec by introducing ShuffleWriterVariant enum - Fix sort shuffle writer to store cumulative batch counts in index instead of placeholder byte offsets - Fix sort shuffle reader to correctly identify partition boundaries using the batch count index - Add comprehensive end-to-end integration tests for sort-based shuffle covering aggregations, GROUP BY, ORDER BY, and comparison with hash-based shuffle Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update writer to use FileWriter instead of StreamWriter - Update reader to use FileReader with set_index() for direct batch access - FileReader supports random access via the IPC footer, eliminating the need to scan through preceding batches to reach the target partition - Index still stores cumulative batch counts for partition boundaries This improves read performance for later partitions (e.g., partition 15 of 16) by directly seeking to the needed batches instead of reading and discarding all preceding data. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use is_multiple_of() instead of manual modulo check. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add FinalizeResult type alias to reduce type complexity - Add #[allow(clippy::too_many_arguments)] for finalize_output function - Use iter_mut().enumerate() instead of index-based loop Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running the tpch benchmark, the --query parameter is now optional. If not specified, all 22 TPC-H queries will be run sequentially. Changes: - Make --query optional for both datafusion and ballista benchmarks - Run all 22 queries when --query is not specified - Only print SQL queries when --debug flag is enabled - Write a single JSON output file for the entire benchmark run - Fix parquet file path resolution for datafusion benchmarks - Simplify output when iterations=1 (no iteration number, no average) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add CLI option to enable sort-based shuffle in the TPC-H benchmark when running against Ballista. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…eader Change sort shuffle partition reading to return a lazy stream that yields batches on-demand rather than collecting all batches into memory upfront. This reduces memory usage for large partitions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add algorithm description from Apache Spark documentation and improve wording for clarity. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update the flight server's do_get handler to detect sort-based shuffle files and read only the relevant partition using the index file. This enables remote shuffle reads for sort-based shuffle. Also add detection in IO_BLOCK_TRANSPORT to return an informative error since block transport doesn't support sort-based shuffle (it transfers the entire file which contains all partitions). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
andygrove
force-pushed
the
sort-based-shuffle
branch
from
January 18, 2026 16:30
e750e7b to
53b5d57
Compare
Use rstest to parameterize sort shuffle tests to run with both local reads and remote reads via the flight service. This ensures the flight service correctly handles sort-based shuffle partition requests. Tests now run in two modes: - Local: reads shuffle data from local filesystem (default) - RemoteFlight: forces remote read through flight service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Summary
This PR implements a sort-based shuffle mechanism for Ballista, similar to Spark's approach. Instead of creating one file per output partition (N×M files for N input partitions and M output partitions), each input partition writes to a single consolidated file with an index file mapping partition IDs to batch ranges.
Key Features
Architecture
Configuration Options
ballista.shuffle.sort_based.enabled- Enable sort-based shuffle (default: false)ballista.shuffle.sort_based.buffer_size- Per-partition buffer size in bytes (default: 1MB)ballista.shuffle.sort_based.memory_limit- Total memory limit for buffers (default: 256MB)Performance
The sort-based shuffle can be more efficient when:
Benchmark (
cargo run --release --bin shuffle_bench):Testing
ballista/client/tests/sort_shuffle.rs)Changes
Core
sort_shufflemodule with all componentsShuffleWritertrait for polymorphic shuffle writer handlingshuffle_reader.rsto detect and read sort-based shuffle formatExecutor
DefaultExecutionEngineto handle bothShuffleWriterExecandSortShuffleWriterExecShuffleWriterVariantenum for type-safe dispatchScheduler/Planner
DistributedPlannerto createSortShuffleWriterExecwhen enabledExecutionStageBuilderto useShuffleWritertraitBenchmarks
shuffle_benchbinary for comparing hash vs sort shuffle performanceRelated Issues
This PR relates to several open issues in apache/datafusion-ballista:
🤖 Generated with Claude Code