@@ -29,7 +29,8 @@ use ballista_core::error::Result;
29
29
30
30
use crate :: state:: session_manager:: create_datafusion_context;
31
31
use ballista_core:: serde:: protobuf:: {
32
- self , job_status, FailedJob , JobStatus , TaskDefinition , TaskStatus ,
32
+ self , job_status, FailedJob , JobStatus , MultiTaskDefinition , TaskDefinition , TaskId ,
33
+ TaskStatus ,
33
34
} ;
34
35
use ballista_core:: serde:: scheduler:: to_proto:: hash_partitioning_to_proto;
35
36
use ballista_core:: serde:: scheduler:: ExecutorMetadata ;
@@ -518,6 +519,7 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U>
518
519
. await
519
520
}
520
521
522
+ #[ allow( dead_code) ]
521
523
#[ cfg( not( test) ) ]
522
524
/// Launch the given task on the specified executor
523
525
pub ( crate ) async fn launch_task (
@@ -544,8 +546,9 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U>
544
546
Ok ( ( ) )
545
547
}
546
548
547
- /// In unit tests, we do not have actual executors running, so it simplifies things to just noop.
549
+ # [ allow ( dead_code ) ]
548
550
#[ cfg( test) ]
551
+ /// In unit tests, we do not have actual executors running, so it simplifies things to just noop.
549
552
pub ( crate ) async fn launch_task (
550
553
& self ,
551
554
_executor : & ExecutorMetadata ,
@@ -623,6 +626,114 @@ impl<T: 'static + AsLogicalPlan, U: 'static + AsExecutionPlan> TaskManager<T, U>
623
626
}
624
627
}
625
628
629
+ #[ cfg( not( test) ) ]
630
+ /// Launch the given tasks on the specified executor
631
+ pub ( crate ) async fn launch_multi_task (
632
+ & self ,
633
+ executor : & ExecutorMetadata ,
634
+ tasks : Vec < Vec < TaskDescription > > ,
635
+ executor_manager : & ExecutorManager ,
636
+ ) -> Result < ( ) > {
637
+ info ! ( "Launching multi task on executor {:?}" , executor. id) ;
638
+ let multi_tasks: Result < Vec < MultiTaskDefinition > > = tasks
639
+ . into_iter ( )
640
+ . map ( |stage_tasks| self . prepare_multi_task_definition ( stage_tasks) )
641
+ . collect ( ) ;
642
+ let multi_tasks = multi_tasks?;
643
+ let mut client = executor_manager. get_client ( & executor. id ) . await ?;
644
+ client
645
+ . launch_multi_task ( protobuf:: LaunchMultiTaskParams {
646
+ multi_tasks,
647
+ scheduler_id : self . scheduler_id . clone ( ) ,
648
+ } )
649
+ . await
650
+ . map_err ( |e| {
651
+ BallistaError :: Internal ( format ! (
652
+ "Failed to connect to executor {}: {:?}" ,
653
+ executor. id, e
654
+ ) )
655
+ } ) ?;
656
+ Ok ( ( ) )
657
+ }
658
+
659
+ #[ cfg( test) ]
660
+ /// Launch the given tasks on the specified executor
661
+ pub ( crate ) async fn launch_multi_task (
662
+ & self ,
663
+ _executor : & ExecutorMetadata ,
664
+ _tasks : Vec < Vec < TaskDescription > > ,
665
+ _executor_manager : & ExecutorManager ,
666
+ ) -> Result < ( ) > {
667
+ Ok ( ( ) )
668
+ }
669
+
670
+ #[ allow( dead_code) ]
671
+ pub fn prepare_multi_task_definition (
672
+ & self ,
673
+ tasks : Vec < TaskDescription > ,
674
+ ) -> Result < MultiTaskDefinition > {
675
+ debug ! ( "Preparing multi task definition for {:?}" , tasks) ;
676
+ if let Some ( task) = tasks. get ( 0 ) {
677
+ let session_id = task. session_id . clone ( ) ;
678
+ let job_id = task. partition . job_id . clone ( ) ;
679
+ let stage_id = task. partition . stage_id ;
680
+ let stage_attempt_num = task. stage_attempt_num ;
681
+
682
+ if let Some ( mut job_info) = self . active_job_cache . get_mut ( & job_id) {
683
+ let plan = if let Some ( plan) = job_info. encoded_stage_plans . get ( & stage_id)
684
+ {
685
+ plan. clone ( )
686
+ } else {
687
+ let mut plan_buf: Vec < u8 > = vec ! [ ] ;
688
+ let plan_proto = U :: try_from_physical_plan (
689
+ task. plan . clone ( ) ,
690
+ self . codec . physical_extension_codec ( ) ,
691
+ ) ?;
692
+ plan_proto. try_encode ( & mut plan_buf) ?;
693
+
694
+ job_info
695
+ . encoded_stage_plans
696
+ . insert ( stage_id, plan_buf. clone ( ) ) ;
697
+
698
+ plan_buf
699
+ } ;
700
+ let output_partitioning =
701
+ hash_partitioning_to_proto ( task. output_partitioning . as_ref ( ) ) ?;
702
+
703
+ let task_ids = tasks
704
+ . iter ( )
705
+ . map ( |task| TaskId {
706
+ task_id : task. task_id as u32 ,
707
+ task_attempt_num : task. task_attempt as u32 ,
708
+ partition_id : task. partition . partition_id as u32 ,
709
+ } )
710
+ . collect ( ) ;
711
+
712
+ let multi_task_definition = MultiTaskDefinition {
713
+ task_ids,
714
+ job_id,
715
+ stage_id : stage_id as u32 ,
716
+ stage_attempt_num : stage_attempt_num as u32 ,
717
+ plan,
718
+ output_partitioning,
719
+ session_id,
720
+ launch_time : SystemTime :: now ( )
721
+ . duration_since ( UNIX_EPOCH )
722
+ . unwrap ( )
723
+ . as_millis ( ) as u64 ,
724
+ props : vec ! [ ] ,
725
+ } ;
726
+ Ok ( multi_task_definition)
727
+ } else {
728
+ Err ( BallistaError :: General ( format ! ( "Cannot prepare multi task definition for job {} which is not in active cache" , job_id) ) )
729
+ }
730
+ } else {
731
+ Err ( BallistaError :: General (
732
+ "Cannot prepare multi task definition for an empty vec" . to_string ( ) ,
733
+ ) )
734
+ }
735
+ }
736
+
626
737
/// Get the `ExecutionGraph` for the given job ID from cache
627
738
pub ( crate ) async fn get_active_execution_graph (
628
739
& self ,
0 commit comments