@@ -152,12 +152,14 @@ impl ExecutionPlan for ShuffleReaderExec {
152152 let max_request_num =
153153 config. ballista_shuffle_reader_maximum_concurrent_requests ( ) ;
154154 let max_message_size = config. ballista_grpc_client_max_message_size ( ) ;
155+ let skip_validation = config. ballista_shuffle_reader_skip_validation ( ) ;
155156
156157 log:: debug!(
157- "ShuffleReaderExec::execute({}) max_request_num: {}, max_message_size: {}" ,
158+ "ShuffleReaderExec::execute({}) max_request_num: {}, max_message_size: {}, skip_validation: {} " ,
158159 task_id,
159160 max_request_num,
160- max_message_size
161+ max_message_size,
162+ skip_validation
161163 ) ;
162164 let mut partition_locations = HashMap :: new ( ) ;
163165 for p in & self . partition [ partition] {
@@ -175,6 +177,9 @@ impl ExecutionPlan for ShuffleReaderExec {
175177 . collect ( ) ;
176178 // Shuffle partitions for evenly send fetching partition requests to avoid hot executors within multiple tasks
177179 partition_locations. shuffle ( & mut rng ( ) ) ;
180+ partition_locations
181+ . iter_mut ( )
182+ . for_each ( |p| p. skip_validation = skip_validation) ;
178183
179184 let response_receiver =
180185 send_fetch_partitions ( partition_locations, max_request_num, max_message_size) ;
@@ -393,6 +398,7 @@ async fn fetch_partition_remote(
393398) -> result:: Result < SendableRecordBatchStream , BallistaError > {
394399 let metadata = & location. executor_meta ;
395400 let partition_id = & location. partition_id ;
401+ let skip_validation = location. skip_validation ;
396402 // TODO for shuffle client connections, we should avoid creating new connections again and again.
397403 // And we should also avoid to keep alive too many connections for long time.
398404 let host = metadata. host . as_str ( ) ;
@@ -411,7 +417,14 @@ async fn fetch_partition_remote(
411417 } ) ?;
412418
413419 ballista_client
414- . fetch_partition ( & metadata. id , partition_id, & location. path , host, port)
420+ . fetch_partition (
421+ & metadata. id ,
422+ partition_id,
423+ & location. path ,
424+ host,
425+ port,
426+ skip_validation,
427+ )
415428 . await
416429}
417430
@@ -421,8 +434,9 @@ async fn fetch_partition_local(
421434 let path = & location. path ;
422435 let metadata = & location. executor_meta ;
423436 let partition_id = & location. partition_id ;
437+ let skip_validation = location. skip_validation ;
424438
425- let reader = fetch_partition_local_inner ( path) . map_err ( |e| {
439+ let reader = fetch_partition_local_inner ( path, skip_validation ) . map_err ( |e| {
426440 // return BallistaError::FetchFailed may let scheduler retry this task.
427441 BallistaError :: FetchFailed (
428442 metadata. id . clone ( ) ,
@@ -436,14 +450,22 @@ async fn fetch_partition_local(
436450
437451fn fetch_partition_local_inner (
438452 path : & str ,
453+ skip_validation : bool ,
439454) -> result:: Result < StreamReader < BufReader < File > > , BallistaError > {
440455 let file = File :: open ( path) . map_err ( |e| {
441456 BallistaError :: General ( format ! ( "Failed to open partition file at {path}: {e:?}" ) )
442457 } ) ?;
443458 let file = BufReader :: new ( file) ;
444- let reader = StreamReader :: try_new ( file, None ) . map_err ( |e| {
445- BallistaError :: General ( format ! ( "Failed to new arrow FileReader at {path}: {e:?}" ) )
446- } ) ?;
459+ // Safety: The caller makes sure ipc file is valid
460+ let reader = unsafe {
461+ StreamReader :: try_new ( file, None )
462+ . map_err ( |e| {
463+ BallistaError :: General ( format ! (
464+ "Failed to new arrow FileReader at {path}: {e:?}"
465+ ) )
466+ } ) ?
467+ . with_skip_validation ( skip_validation)
468+ } ;
447469 Ok ( reader)
448470}
449471
@@ -567,6 +589,7 @@ mod tests {
567589 } ,
568590 partition_stats : Default :: default ( ) ,
569591 path : "test_path" . to_string ( ) ,
592+ skip_validation : true ,
570593 } )
571594 }
572595
@@ -601,8 +624,7 @@ mod tests {
601624 test_send_fetch_partitions ( 4 , 10 ) . await ;
602625 }
603626
604- #[ tokio:: test]
605- async fn test_read_local_shuffle ( ) {
627+ async fn test_read_local_shuffle_impl ( skip_validation : bool ) {
606628 let session_ctx = SessionContext :: new ( ) ;
607629 let task_ctx = session_ctx. task_ctx ( ) ;
608630 let work_dir = TempDir :: new ( ) . unwrap ( ) ;
@@ -629,7 +651,7 @@ mod tests {
629651
630652 // from to input partitions test the first one with two batches
631653 let file_path = path. value ( 0 ) ;
632- let reader = fetch_partition_local_inner ( file_path) . unwrap ( ) ;
654+ let reader = fetch_partition_local_inner ( file_path, skip_validation ) . unwrap ( ) ;
633655
634656 let mut stream: Pin < Box < dyn RecordBatchStream + Send > > =
635657 async { Box :: pin ( LocalShuffleStream :: new ( reader) ) } . await ;
@@ -645,6 +667,16 @@ mod tests {
645667 }
646668 }
647669
670+ #[ tokio:: test]
671+ async fn test_read_local_shuffle_with_validation ( ) {
672+ test_read_local_shuffle_impl ( false ) . await ;
673+ }
674+
675+ #[ tokio:: test]
676+ async fn test_read_local_shuffle_skip_validation ( ) {
677+ test_read_local_shuffle_impl ( true ) . await ;
678+ }
679+
648680 async fn test_send_fetch_partitions ( max_request_num : usize , partition_num : usize ) {
649681 let schema = get_test_partition_schema ( ) ;
650682 let data_array = Int32Array :: from ( vec ! [ 1 ] ) ;
@@ -693,6 +725,7 @@ mod tests {
693725 } ,
694726 partition_stats : Default :: default ( ) ,
695727 path : path. clone ( ) ,
728+ skip_validation : true ,
696729 } )
697730 . collect ( )
698731 }
0 commit comments