Upgrade Guides#
Ballista 54.0.0#
Note: Ballista 54.0.0 has not been released yet. The information provided
in this section pertains to features and changes that have already been merged
to the main branch and are awaiting release in this version.
For library and embedding users#
Upgrade to DataFusion 54#
Ballista 54.0.0 upgrades its DataFusion dependency to 54.0.0. Code built on
ballista-core / DataFusion APIs must move with it. See DataFusion’s own
Upgrade Guide for 54.0.0
for the DataFusion-side API changes.
job_id is now a newtype#
Scheduler job identifiers are no longer bare Strings. ballista-core now
exports a transparent JobId newtype (ballista_core::JobId) so a job id can
no longer be confused with another string identifier at the type level. Public
signatures that previously carried a String/&str job id now carry a JobId
/ &JobId — for example DistributedQueryExec::job_id() now returns
Option<JobId> instead of Option<String>. Construct one with
JobId::new(...) or .into(), and recover the inner string with .as_str()
or .into_inner().
// before
let id: Option<String> = query_exec.job_id();
// after
use ballista_core::JobId;
let id: Option<JobId> = query_exec.job_id();
let id_str: Option<String> = id.map(|id| id.into_inner());
For cluster operators#
CORS origins and methods are configured via CLI flags#
The scheduler REST API no longer reads CORS configuration from environment
variables. The BALLISTA_CORS_ALLOWED_ORIGINS and
BALLISTA_CORS_ALLOWED_METHODS environment variables are removed and replaced
by the --cors-allowed-origins and --cors-allowed-methods scheduler CLI
flags (each a comma-separated list; * allows any). If you set these
environment variables, move the values to the flags — otherwise the scheduler
falls back to its defaults (origins http://localhost:8080 and
https://nightlies.apache.org; methods GET, PATCH, OPTIONS).
# before (environment variables)
BALLISTA_CORS_ALLOWED_ORIGINS=https://example.com \
BALLISTA_CORS_ALLOWED_METHODS=GET,PATCH \
ballista-scheduler
# after (scheduler CLI flags)
ballista-scheduler \
--cors-allowed-origins https://example.com \
--cors-allowed-methods GET,PATCH
Planner and execution behavior changes#
The static planner now broadcasts small join build sides#
Ballista previously disabled CollectLeft broadcast joins entirely (both
datafusion.optimizer.hash_join_single_partition_threshold and
hash_join_single_partition_threshold_rows defaulted to 0). In 54.0.0
those defaults are raised to 10 MB (10485760) and 1000000 rows, and the
static DefaultDistributedPlanner now converts a SortMergeJoinExec whose
smaller side fits under ballista.optimizer.broadcast_join_threshold_bytes
(default 10 MB) into a broadcast CollectLeft hash join. This conversion is
governed by the new ballista.optimizer.broadcast_sort_merge_join_enabled
config key, which defaults to true.
The consequence is that join plans — and therefore performance and shuffle
behavior — change on upgrade even with AQE off. Broadcast is applied only
to join types that are safe to broadcast (inner and right-side variants); other
join types remain repartitioned. To restore the previous behavior, set
ballista.optimizer.broadcast_sort_merge_join_enabled = false,
ballista.optimizer.broadcast_join_threshold_bytes = 0,
datafusion.optimizer.hash_join_single_partition_threshold = 0, and
hash_join_single_partition_threshold_rows = 0.
Serialized empty projections#
The plan serialization for a filter that projects to zero columns changed. In
53.x an empty projection (Some([])) and “all columns” (None) both encoded
to an empty list and decoded back to None, shifting downstream column indices;
the scheduler now rewrites such filters into a serde-safe form before
serialization. Together with the DataFusion 54 protobuf bump, this means a
54.0.0 scheduler and a 53.x executor (or vice versa) cannot reliably
exchange serialized plans. Upgrade schedulers and executors together — do not
run a mixed-version cluster across this upgrade.
AQE join behavior (opt-in)#
If you have enabled ballista.planner.adaptive.enabled = true, adaptive join
selection now delays the join decision and can promote a small build side to a
broadcast (CollectLeft) hash join at runtime, and empty-join inputs are
short-circuited by the propagate-empty rule. This changes the runtime join
plans (and their results’ timing/shape) for adaptive clusters; it is gated by
ballista.planner.adaptive_join.enabled (default true). Clusters using the
default (AQE off) are unaffected.