andygrove commented on code in PR #1916:
URL: 
https://github.com/apache/datafusion-ballista/pull/1916#discussion_r4165161843


##########
ballista/scheduler/src/state/execution_stage.rs:
##########
@@ -1509,6 +1544,88 @@ mod tests {
         });
     }
 
+    /// Build a running stage over a two-column schema plus a successful task
+    /// reporting the given per-column null counts.
+    fn stage_with_col_stats(tasks: Vec<Vec<TaskColumnStats>>) -> RunningStage {
+        use datafusion::arrow::datatypes::{DataType, Field, Schema};
+        let schema = Arc::new(Schema::new(vec![
+            Field::new("a", DataType::UInt32, true),
+            Field::new("b", DataType::UInt32, true),
+        ]));
+        let plan: Arc<dyn ExecutionPlan> = Arc::new(EmptyExec::new(schema));
+        let mut stage = RunningStage::new(
+            1,
+            0,
+            plan,
+            tasks.len(),
+            vec![],
+            HashMap::new(),
+            Arc::new(SessionConfig::default()),
+        );
+        for (task_id, task_column_stats) in tasks.into_iter().enumerate() {
+            stage.task_infos.push(TaskInfo {
+                task_id,
+                scheduled_time: 50,
+                launch_time: 100,
+                start_exec_time: 200,
+                end_exec_time: 300,
+                finish_time: 300,
+                task_status: task_status::Status::Successful(SuccessfulTask {
+                    executor_id: "executor-1".to_string(),
+                    partitions: vec![],
+                    runtime_stats: vec![],
+                    task_column_stats,
+                    window_state: vec![],
+                }),
+                global_input_partition_ids: vec![task_id],
+                vcores_consumed: 1,
+            });
+        }
+        stage
+    }
+
+    fn col(column: u32, null_count: u64) -> TaskColumnStats {
+        TaskColumnStats {
+            column,
+            null_count,
+            sketches: vec![],
+        }
+    }
+
+    #[test]
+    fn test_to_successful_folds_column_null_counts_across_tasks() {
+        let stage = stage_with_col_stats(vec![
+            vec![col(0, 1), col(1, 2)],
+            vec![col(0, 3), col(1, 4)],
+        ]);
+        let successful = stage.to_successful();
+        assert_eq!(
+            successful.output_column_stats[0].null_count,
+            Precision::Exact(4)
+        );
+        assert_eq!(
+            successful.output_column_stats[1].null_count,
+            Precision::Exact(6)
+        );
+    }
+
+    #[test]
+    fn test_to_successful_marks_unreported_column_absent() {

Review Comment:
   Nice test. It might be worth one more case next to it, where a task reports 
a `column` past the schema width. `get_mut` handles that now, and a test would 
keep it from turning back into a panic if this loop gets refactored later.



##########
ballista/scheduler/src/state/execution_stage.rs:
##########
@@ -267,6 +268,8 @@ pub struct SuccessfulStage {
     pub stage_metrics: Vec<MetricsSet>,
     /// [SessionConfig] used for this stage
     pub session_config: Arc<SessionConfig>,
+    /// container to store col stats per stage

Review Comment:
   Could this doc say what the vec holds? Something like one entry per column 
of the stage's output schema, with `null_count` only `Exact` when every 
successful task reported that column. That'll help whoever writes the first 
consumer.



##########
ballista/core/src/execution_plans/sort_shuffle/writer.rs:
##########
@@ -630,10 +644,14 @@ impl SortShuffleWriterExec {
             // `MemoryPool` as the sole spill trigger.
             let memory_limit = config.memory_limit_per_task_bytes;
             let per_task_budget_enabled = memory_limit > 0;
+            let mut null_counts = vec![0u64; schema.fields().len()];
 
             while let Some(result) = stream.next().await {
                 let input_batch = result?;
                 metrics.input_rows.add(input_batch.num_rows());
+                for (i, col) in input_batch.columns().iter().enumerate() {
+                    null_counts[i] += col.logical_null_count() as u64;

Review Comment:
   Thanks for switching this. A small test with a `DataType::Null` column would 
capture why `logical_null_count()` matters here. A `NullArray::new(3)` column 
should report 3, where `null_count()` reported 0.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to