micromegas_analytics/lakehouse/
perfetto_trace_table_function.rs1use super::{
2 lakehouse_context::LakehouseContext, partition_cache::QueryPartitionProvider,
3 view_factory::ViewFactory,
4};
5use crate::{
6 dfext::expressions::{exp_to_string, exp_to_timestamp},
7 time::TimeRange,
8};
9use datafusion::{
10 arrow::datatypes::{DataType, Field, Schema},
11 catalog::{TableFunctionArgs, TableFunctionImpl, TableProvider},
12 common::plan_err,
13};
14use micromegas_tracing::prelude::*;
15use std::sync::Arc;
16
17#[derive(Debug)]
35pub struct PerfettoTraceTableFunction {
36 lakehouse: Arc<LakehouseContext>,
37 view_factory: Arc<ViewFactory>,
38 part_provider: Arc<dyn QueryPartitionProvider>,
39}
40
41impl PerfettoTraceTableFunction {
42 pub fn new(
43 lakehouse: Arc<LakehouseContext>,
44 view_factory: Arc<ViewFactory>,
45 part_provider: Arc<dyn QueryPartitionProvider>,
46 ) -> Self {
47 Self {
48 lakehouse,
49 view_factory,
50 part_provider,
51 }
52 }
53
54 pub fn output_schema() -> Arc<Schema> {
56 Arc::new(Schema::new(vec![
57 Field::new("chunk_id", DataType::Int32, false),
58 Field::new("chunk_data", DataType::Binary, false),
59 ]))
60 }
61}
62
63impl TableFunctionImpl for PerfettoTraceTableFunction {
64 #[span_fn]
65 fn call_with_args(
66 &self,
67 args: TableFunctionArgs,
68 ) -> datafusion::error::Result<Arc<dyn TableProvider>> {
69 let exprs = args.exprs();
70 let arg1 = exprs.first().map(exp_to_string);
72 let Some(Ok(process_id)) = arg1 else {
73 return plan_err!(
74 "First argument to perfetto_trace_chunks must be a string (the process ID), given {:?}",
75 arg1
76 );
77 };
78
79 let arg2 = exprs.get(1).map(exp_to_string);
81 let Some(Ok(span_types_str)) = arg2 else {
82 return plan_err!(
83 "Second argument to perfetto_trace_chunks must be a string ('thread', 'async', or 'both'), given {:?}",
84 arg2
85 );
86 };
87
88 let span_types = match span_types_str.as_str() {
89 "thread" => SpanTypes::Thread,
90 "async" => SpanTypes::Async,
91 "both" => SpanTypes::Both,
92 _ => {
93 return plan_err!(
94 "span_types must be 'thread', 'async', or 'both', given: {}",
95 span_types_str
96 );
97 }
98 };
99
100 let arg3 = exprs.get(2).map(exp_to_timestamp);
102 let Some(Ok(start_time)) = arg3 else {
103 return plan_err!(
104 "Third argument to perfetto_trace_chunks must be a timestamp (start time), given {:?}",
105 arg3
106 );
107 };
108
109 let arg4 = exprs.get(3).map(exp_to_timestamp);
111 let Some(Ok(end_time)) = arg4 else {
112 return plan_err!(
113 "Fourth argument to perfetto_trace_chunks must be a timestamp (end time), given {:?}",
114 arg4
115 );
116 };
117
118 let time_range = TimeRange {
120 begin: start_time,
121 end: end_time,
122 };
123
124 let execution_plan = Arc::new(PerfettoTraceExecutionPlan::new(
126 Self::output_schema(),
127 process_id,
128 span_types,
129 time_range,
130 self.lakehouse.clone(),
131 self.view_factory.clone(),
132 self.part_provider.clone(),
133 ));
134
135 Ok(Arc::new(PerfettoTraceTableProvider::new(execution_plan)))
137 }
138}
139
140use super::perfetto_trace_execution_plan::{
142 PerfettoTraceExecutionPlan, PerfettoTraceTableProvider, SpanTypes,
143};