-
Notifications
You must be signed in to change notification settings - Fork 0
1911: perf: prune irrelevant partitions task #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2afd98a
cb95ac0
4308487
f403a3b
b1cc69c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| The AI agents should never link to any issue or a pull request | ||
| in any GitHub repository in the code reviews! | ||
|
|
||
| The AI agents should not review AI agents' config files like CLAUDE.md or AGENTS.md! | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| The AI agents should never link to any issue or a pull request | ||
| in any GitHub repository in the code reviews! | ||
|
|
||
| The AI agents should not review AI agents' config files like CLAUDE.md or AGENTS.md! | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| The AI agents should never link to any issue or a pull request | ||
| in any GitHub repository in the code reviews! | ||
|
|
||
| The AI agents should not review AI agents' config files like CLAUDE.md or AGENTS.md! | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,17 +28,19 @@ use crate::state::executor_manager::ExecutorManager; | |
| use ballista_core::JobStatusSubscriber; | ||
| use ballista_core::error::BallistaError; | ||
| use ballista_core::error::Result; | ||
| use ballista_core::execution_plans::ShuffleReaderExec; | ||
| use ballista_core::extension::{SessionConfigExt, SessionConfigHelperExt}; | ||
| use ballista_core::serde::BallistaCodec; | ||
| use ballista_core::serde::protobuf::{ | ||
| JobStatus, MultiTaskDefinition, TaskDefinition, TaskId, TaskStatus, job_status, | ||
| }; | ||
| use ballista_core::serde::scheduler::ExecutorMetadata; | ||
| use dashmap::DashMap; | ||
| use datafusion::common::tree_node::{Transformed, TreeNode}; | ||
| use datafusion::execution::config::SessionConfig; | ||
| use datafusion::execution::context::SessionContext; | ||
| use datafusion::logical_expr::LogicalPlan; | ||
| use datafusion::physical_plan::ExecutionPlan; | ||
| use datafusion::physical_plan::{ExecutionPlan, ExecutionPlanProperties}; | ||
| use datafusion_proto::logical_plan::AsLogicalPlan; | ||
| use datafusion_proto::physical_plan::{AsExecutionPlan, PhysicalExtensionCodec}; | ||
| use datafusion_proto::protobuf::PhysicalPlanNode; | ||
|
|
@@ -163,12 +165,64 @@ impl JobInfoCache { | |
| encoded_stage_plans: HashMap::new(), | ||
| } | ||
| } | ||
|
|
||
| #[cfg(feature = "disable-stage-plan-cache")] | ||
| fn partition_prune_helper( | ||
| partition_ids: &[usize], | ||
| plan: &Arc<dyn ExecutionPlan>, | ||
| ) -> Result<Arc<dyn ExecutionPlan>> { | ||
| let n = plan.output_partitioning().partition_count(); | ||
| let wanted: HashSet<usize> = partition_ids.iter().copied().collect(); | ||
| Ok(plan | ||
| .clone() | ||
| .transform_up(|node| { | ||
| let Some(r) = node.as_any().downcast_ref::<ShuffleReaderExec>() else { | ||
| return Ok(Transformed::no(node)); | ||
| }; | ||
| if r.broadcast || r.partition.len() != n { | ||
| return Ok(Transformed::no(node)); | ||
| } | ||
|
|
||
| let partition = r | ||
| .partition | ||
| .iter() | ||
| .enumerate() | ||
| .map(|(i, loc)| { | ||
| if wanted.contains(&i) { | ||
| loc.clone() | ||
| } else { | ||
| vec![] | ||
| } | ||
| }) | ||
| .collect(); | ||
|
Comment on lines
+175
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since Ok(plan
.clone()
.transform_up(|node| {
let Some(r) = node.as_any().downcast_ref::<ShuffleReaderExec>() else {
return Ok(Transformed::no(node));
};
if r.broadcast || r.partition.len() != n {
return Ok(Transformed::no(node));
}
let partition = r
.partition
.iter()
.enumerate()
.map(|(i, loc)| {
if partition_ids.contains(&i) {
loc.clone()
} else {
vec![]
}
})
.collect(); |
||
|
|
||
| let reader = match r.coalesce.clone() { | ||
| Some(c) => ShuffleReaderExec::try_new_coalesced( | ||
| r.stage_id, | ||
| partition, | ||
| c, | ||
| r.schema(), | ||
| r.properties().output_partitioning().clone(), | ||
| )?, | ||
| None => ShuffleReaderExec::try_new( | ||
| r.stage_id, | ||
| partition, | ||
| r.schema(), | ||
| r.properties().output_partitioning().clone(), | ||
| )?, | ||
| }; | ||
| Ok(Transformed::yes(Arc::new(reader) as Arc<dyn ExecutionPlan>)) | ||
| })? | ||
| .data) | ||
| } | ||
|
|
||
| #[cfg(not(feature = "disable-stage-plan-cache"))] | ||
| fn encode_stage_plan<U: AsExecutionPlan>( | ||
| &mut self, | ||
| stage_id: usize, | ||
| plan: &Arc<dyn ExecutionPlan>, | ||
| codec: &dyn PhysicalExtensionCodec, | ||
| _partition_ids: &[usize], | ||
| ) -> Result<Vec<u8>> { | ||
| if let Some(plan) = self.encoded_stage_plans.get(&stage_id) { | ||
| Ok(plan.clone()) | ||
|
|
@@ -177,7 +231,6 @@ impl JobInfoCache { | |
| let plan_proto = U::try_from_physical_plan(plan.clone(), codec)?; | ||
| plan_proto.try_encode(&mut plan_buf)?; | ||
| self.encoded_stage_plans.insert(stage_id, plan_buf.clone()); | ||
|
|
||
| Ok(plan_buf) | ||
| } | ||
| } | ||
|
|
@@ -188,9 +241,11 @@ impl JobInfoCache { | |
| _stage_id: usize, | ||
| plan: &Arc<dyn ExecutionPlan>, | ||
| codec: &dyn PhysicalExtensionCodec, | ||
| partition_ids: &[usize], | ||
| ) -> Result<Vec<u8>> { | ||
| let mut plan_buf: Vec<u8> = vec![]; | ||
| let plan_proto = U::try_from_physical_plan(plan.clone(), codec)?; | ||
| let pruned_plan = Self::partition_prune_helper(partition_ids, plan)?; | ||
| let plan_proto = U::try_from_physical_plan(pruned_plan, codec)?; | ||
| plan_proto.try_encode(&mut plan_buf)?; | ||
|
|
||
| Ok(plan_buf) | ||
|
|
@@ -653,6 +708,7 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U> | |
| stage_id, | ||
| &task.plan, | ||
| self.codec.physical_extension_codec(), | ||
| &[task.partition.partition_id], | ||
| )?; | ||
|
|
||
| let task_definition = TaskDefinition { | ||
|
|
@@ -708,6 +764,10 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U> | |
| &self, | ||
| tasks: Vec<TaskDescription>, | ||
| ) -> Result<Vec<MultiTaskDefinition>> { | ||
| let partition_ids: Vec<usize> = tasks | ||
| .iter() | ||
| .map(|task| task.partition.partition_id) | ||
| .collect(); | ||
| if let Some(task) = tasks.first() { | ||
| let session_id = task.session_id.clone(); | ||
| let job_id = task.partition.job_id.clone(); | ||
|
|
@@ -730,6 +790,7 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U> | |
| stage_id, | ||
| &task.plan, | ||
| self.codec.physical_extension_codec(), | ||
| &partition_ids, | ||
| )?; | ||
|
|
||
| let launch_time = SystemTime::now() | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ballista/scheduler/src/state/task_manager.rs:174:partition_prune_helpercan turn non-wantedShuffleReaderExec.partition[i]entries into empty location lists, which will silently produce empty input if a non-included partition ever gets executed (or if an out-of-rangepartition_idis passed). Consider validating thatpartition_idsare in-range and correspond exactly to the partitions that will be executed with this encoded plan.Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.