micromegas_analytics/lakehouse/
retire_partitions_table_function.rs1use anyhow::Context;
2use chrono::DateTime;
3use chrono::Utc;
4use datafusion::catalog::TableFunctionArgs;
5use datafusion::catalog::TableFunctionImpl;
6use datafusion::catalog::TableProvider;
7use datafusion::common::plan_err;
8use micromegas_ingestion::data_lake_connection::DataLakeConnection;
9use micromegas_tracing::prelude::*;
10use std::sync::Arc;
11
12use crate::dfext::expressions::exp_to_string;
13use crate::dfext::expressions::exp_to_timestamp;
14use crate::dfext::log_stream_table_provider::LogStreamTableProvider;
15use crate::dfext::task_log_exec_plan::TaskLogExecPlan;
16use crate::response_writer::LogSender;
17use crate::response_writer::Logger;
18
19use super::write_partition::{RetireMatch, retire_partitions};
20
21#[derive(Debug)]
23pub struct RetirePartitionsTableFunction {
24 lake: Arc<DataLakeConnection>,
25}
26
27impl RetirePartitionsTableFunction {
28 pub fn new(lake: Arc<DataLakeConnection>) -> Self {
29 Self { lake }
30 }
31}
32
33async fn retire_partitions_impl(
34 lake: Arc<DataLakeConnection>,
35 view_set_name: &str,
36 view_instance_id: &str,
37 begin_insert_time: DateTime<Utc>,
38 end_insert_time: DateTime<Utc>,
39 logger: Arc<dyn Logger>,
40) -> anyhow::Result<()> {
41 let mut tr = lake.db_pool.begin().await?;
42 retire_partitions(
45 &mut tr,
46 view_set_name,
47 view_instance_id,
48 begin_insert_time,
49 end_insert_time,
50 RetireMatch::Containment,
51 &[],
52 logger,
53 )
54 .await?;
55 tr.commit().await.with_context(|| "commit")?;
56 Ok(())
57}
58
59impl TableFunctionImpl for RetirePartitionsTableFunction {
60 fn call_with_args(
61 &self,
62 args: TableFunctionArgs,
63 ) -> datafusion::error::Result<Arc<dyn TableProvider>> {
64 let args = args.exprs();
65 let Some(view_set_name) = args.first().map(exp_to_string).transpose()? else {
67 return plan_err!("Missing first argument, expected view_set_name: String");
68 };
69 let Some(view_instance_id) = args.get(1).map(exp_to_string).transpose()? else {
70 return plan_err!("Missing 2nd argument, expected view_instance_id: String");
71 };
72 let Some(begin) = args.get(2).map(exp_to_timestamp).transpose()? else {
73 return plan_err!("Missing 3rd argument, expected a UTC nanoseconds timestamp");
74 };
75 let Some(end) = args.get(3).map(exp_to_timestamp).transpose()? else {
76 return plan_err!("Missing 4th argument, expected a UTC nanoseconds timestamp");
77 };
78
79 let lake = self.lake.clone();
80
81 let spawner = move || {
82 let (tx, rx) = tokio::sync::mpsc::channel(100);
83 let logger = Arc::new(LogSender::new(tx));
84 spawn_with_context(async move {
85 if let Err(e) = retire_partitions_impl(
86 lake,
87 &view_set_name,
88 &view_instance_id,
89 begin,
90 end,
91 logger,
92 )
93 .await
94 .with_context(|| "retire_partitions_impl")
95 {
96 error!("{e:?}");
97 }
98 });
99 rx
100 };
101
102 Ok(Arc::new(LogStreamTableProvider {
103 log_stream: Arc::new(TaskLogExecPlan::new(Box::new(spawner))),
104 }))
105 }
106}