Skip to content

Commit 8026cc2

Browse files
Log DataFusion rendezvous task routing
1 parent 3521b3f commit 8026cc2

1 file changed

Lines changed: 82 additions & 14 deletions

File tree

quickwit/quickwit-df-core/src/task_estimator.rs

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,35 @@ impl TaskEstimator for DataSourceExecPartitionEstimator {
7171

7272
fn route_tasks(&self, routing_ctx: &TaskRoutingContext<'_>) -> DFResult<Option<Vec<Url>>> {
7373
if routing_ctx.available_urls.is_empty() {
74+
log_routing_fallback(routing_ctx, "no_available_workers");
7475
return Ok(None);
7576
}
76-
let Some(file_scan) = single_file_scan_config(routing_ctx.plan) else {
77+
let mut file_scans = Vec::new();
78+
collect_file_scan_configs(routing_ctx.plan, &mut file_scans);
79+
let [file_scan] = file_scans.as_slice() else {
80+
let reason = if file_scans.is_empty() {
81+
"no_file_scan_config"
82+
} else {
83+
"multiple_file_scan_configs"
84+
};
85+
log_routing_fallback(routing_ctx, reason);
7786
return Ok(None);
7887
};
7988
let task_affinities = file_scan_task_affinities(file_scan, routing_ctx.task_count);
8089
if task_affinities.len() != routing_ctx.task_count {
90+
tracing::info!(
91+
strategy = "file_rendezvous",
92+
reason = "task_affinity_count_mismatch",
93+
task_count = routing_ctx.task_count,
94+
task_affinity_count = task_affinities.len(),
95+
available_worker_count = routing_ctx.available_urls.len(),
96+
"datafusion task routing fell back to default routing"
97+
);
8198
return Ok(None);
8299
}
83-
Ok(Some(route_by_rendezvous(
84-
&task_affinities,
85-
routing_ctx.available_urls,
86-
)))
100+
let routes = route_by_rendezvous(&task_affinities, routing_ctx.available_urls);
101+
log_rendezvous_routes(routing_ctx, &task_affinities, &routes);
102+
Ok(Some(routes))
87103
}
88104
}
89105

@@ -93,15 +109,6 @@ struct TaskAffinity {
93109
affinity_key: String,
94110
}
95111

96-
fn single_file_scan_config(plan: &Arc<dyn ExecutionPlan>) -> Option<&FileScanConfig> {
97-
let mut file_scans = Vec::new();
98-
collect_file_scan_configs(plan, &mut file_scans);
99-
match file_scans.as_slice() {
100-
[file_scan] => Some(*file_scan),
101-
_ => None,
102-
}
103-
}
104-
105112
fn collect_file_scan_configs<'a>(
106113
plan: &'a Arc<dyn ExecutionPlan>,
107114
file_scans: &mut Vec<&'a FileScanConfig>,
@@ -211,6 +218,67 @@ fn rendezvous_affinity(url: &Url, key: &str) -> u64 {
211218
state.finish()
212219
}
213220

221+
fn affinity_fingerprint(key: &str) -> u64 {
222+
let mut state = SipHasher::new();
223+
key.hash(&mut state);
224+
state.finish()
225+
}
226+
227+
fn log_routing_fallback(routing_ctx: &TaskRoutingContext<'_>, reason: &'static str) {
228+
tracing::info!(
229+
strategy = "file_rendezvous",
230+
reason,
231+
task_count = routing_ctx.task_count,
232+
available_worker_count = routing_ctx.available_urls.len(),
233+
"datafusion task routing fell back to default routing"
234+
);
235+
}
236+
237+
fn log_rendezvous_routes(
238+
routing_ctx: &TaskRoutingContext<'_>,
239+
task_affinities: &[TaskAffinity],
240+
routes: &[Url],
241+
) {
242+
const ROUTE_SAMPLE_SIZE: usize = 16;
243+
244+
let mut route_distribution: Vec<(&str, usize)> = Vec::new();
245+
for route in routes {
246+
let route = route.as_str();
247+
match route_distribution
248+
.iter_mut()
249+
.find(|(worker_url, _)| *worker_url == route)
250+
{
251+
Some((_, task_count)) => *task_count += 1,
252+
None => route_distribution.push((route, 1)),
253+
}
254+
}
255+
route_distribution.sort_unstable_by(|(left, _), (right, _)| left.cmp(right));
256+
257+
let route_sample: Vec<(usize, u64, &str)> = task_affinities
258+
.iter()
259+
.take(ROUTE_SAMPLE_SIZE)
260+
.filter_map(|task_affinity| {
261+
routes.get(task_affinity.task_index).map(|route| {
262+
(
263+
task_affinity.task_index,
264+
affinity_fingerprint(&task_affinity.affinity_key),
265+
route.as_str(),
266+
)
267+
})
268+
})
269+
.collect();
270+
271+
tracing::info!(
272+
strategy = "file_rendezvous",
273+
task_count = routes.len(),
274+
available_worker_count = routing_ctx.available_urls.len(),
275+
route_sample_size = route_sample.len(),
276+
route_distribution = ?route_distribution,
277+
route_sample = ?route_sample,
278+
"datafusion task routing selected workers"
279+
);
280+
}
281+
214282
#[cfg(test)]
215283
mod tests {
216284
use super::*;

0 commit comments

Comments
 (0)