Skip to content

Commit 26c7ac4

Browse files
authored
chore: add VACUUM TEMPORARY TABLES command (#18349)
* support limit * new syntax
1 parent ffdd2f8 commit 26c7ac4

File tree

2 files changed

+80
-8
lines changed

2 files changed

+80
-8
lines changed

src/query/ast/src/parser/statement.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,18 @@ pub fn statement_body(i: Input) -> IResult<Statement> {
19041904
},
19051905
);
19061906

1907+
let vacuum_temporary_tables = map(
1908+
rule! {
1909+
VACUUM ~ TEMPORARY ~ TABLES ~ ( LIMIT ~ ^#literal_u64 )?
1910+
},
1911+
|(_, _, _, opt_limit)| {
1912+
Statement::Call(CallStmt {
1913+
name: "fuse_vacuum_temporary_table".to_string(),
1914+
args: opt_limit.map(|v| v.1.to_string()).into_iter().collect(),
1915+
})
1916+
},
1917+
);
1918+
19071919
let presign = map(
19081920
rule! {
19091921
PRESIGN ~ ( #presign_action )?
@@ -2726,6 +2738,7 @@ AS
27262738
| #call_procedure : "`CALL PROCEDURE <procedure_name>()`"
27272739
),
27282740
rule!(#comment),
2741+
rule!(#vacuum_temporary_tables),
27292742
))(i)
27302743
}
27312744

src/query/storages/fuse/src/table_functions/fuse_vacuum_temporary_table.rs

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ use std::collections::HashSet;
1616
use std::sync::Arc;
1717

1818
use databend_common_catalog::plan::DataSourcePlan;
19+
use databend_common_catalog::table_args::TableArgs;
1920
use databend_common_exception::ErrorCode;
2021
use databend_common_exception::Result;
22+
use databend_common_expression::types::NumberScalar;
2123
use databend_common_expression::types::StringType;
2224
use databend_common_expression::DataBlock;
2325
use databend_common_expression::FromData;
26+
use databend_common_expression::Scalar;
2427
use databend_common_expression::TableDataType;
2528
use databend_common_expression::TableField;
2629
use databend_common_expression::TableSchemaRef;
@@ -33,8 +36,10 @@ use log::info;
3336

3437
use crate::sessions::TableContext;
3538
use crate::table_functions::SimpleTableFunc;
36-
use crate::table_functions::TableArgs;
37-
pub struct FuseVacuumTemporaryTable;
39+
40+
pub struct FuseVacuumTemporaryTable {
41+
limit: Option<u64>,
42+
}
3843

3944
#[async_trait::async_trait]
4045
impl SimpleTableFunc for FuseVacuumTemporaryTable {
@@ -43,7 +48,11 @@ impl SimpleTableFunc for FuseVacuumTemporaryTable {
4348
}
4449

4550
fn table_args(&self) -> Option<TableArgs> {
46-
None
51+
self.limit.map(|limit| {
52+
TableArgs::new_positioned(vec![databend_common_catalog::table_args::u64_literal(
53+
limit,
54+
)])
55+
})
4756
}
4857

4958
fn schema(&self) -> TableSchemaRef {
@@ -62,17 +71,39 @@ impl SimpleTableFunc for FuseVacuumTemporaryTable {
6271
.await?;
6372
let client_session_mgr = UserApiProvider::instance().client_session_api(&ctx.get_tenant());
6473
let mut user_session_ids = HashSet::new();
74+
let mut inactive_user_session_ids = HashSet::new();
6575
while let Some(entry) = lister.try_next().await? {
76+
if entry.metadata().is_dir() {
77+
continue;
78+
}
6679
let path = entry.path();
6780
let parts: Vec<_> = path.split('/').collect();
6881
if parts.len() < 3 {
6982
return Err(ErrorCode::Internal(format!(
7083
"invalid path for temp table: {path}"
7184
)));
7285
};
73-
user_session_ids.insert((parts[1].to_string(), parts[2].to_string()));
86+
let user_name = parts[1].to_string();
87+
let session_id = parts[2].to_string();
88+
if user_session_ids.contains(&(user_name.clone(), session_id.clone())) {
89+
continue;
90+
}
91+
user_session_ids.insert((user_name.clone(), session_id.clone()));
92+
if client_session_mgr
93+
.get_client_session(&user_name, &session_id)
94+
.await?
95+
.is_none()
96+
{
97+
inactive_user_session_ids.insert((user_name, session_id));
98+
if inactive_user_session_ids.len() >= self.limit.unwrap_or(u64::MAX) as usize {
99+
break;
100+
}
101+
}
74102
}
75-
for (user_name, session_id) in user_session_ids {
103+
104+
let session_num = inactive_user_session_ids.len();
105+
106+
for (user_name, session_id) in inactive_user_session_ids {
76107
if client_session_mgr
77108
.get_client_session(&user_name, &session_id)
78109
.await?
@@ -86,15 +117,43 @@ impl SimpleTableFunc for FuseVacuumTemporaryTable {
86117
op.remove_all(&path).await?;
87118
}
88119
}
89-
let col: Vec<String> = vec!["Ok".to_owned()];
120+
let col: Vec<String> = vec![format!(
121+
"Ok: processed temporary tables from {} inactive sessions",
122+
session_num
123+
)];
90124

91125
Ok(Some(DataBlock::new_from_columns(vec![
92126
StringType::from_data(col),
93127
])))
94128
}
95129

96-
fn create(_func_name: &str, _table_args: TableArgs) -> Result<Self>
130+
fn create(func_name: &str, table_args: TableArgs) -> Result<Self>
97131
where Self: Sized {
98-
Ok(Self)
132+
let limit = match table_args.positioned.len() {
133+
0 => None,
134+
1 => {
135+
let args = table_args.expect_all_positioned(func_name, Some(1))?;
136+
let limit_val = match &args[0] {
137+
Scalar::Number(NumberScalar::UInt64(val)) => *val,
138+
Scalar::Number(NumberScalar::UInt32(val)) => *val as u64,
139+
Scalar::Number(NumberScalar::UInt16(val)) => *val as u64,
140+
Scalar::Number(NumberScalar::UInt8(val)) => *val as u64,
141+
Scalar::String(val) => val.parse::<u64>()?,
142+
_ => {
143+
return Err(ErrorCode::BadArguments(format!(
144+
"invalid value {:?} expect to be unsigned integer literal.",
145+
args[0]
146+
)))
147+
}
148+
};
149+
Some(limit_val)
150+
}
151+
_ => {
152+
return Err(ErrorCode::NumberArgumentsNotMatch(
153+
"Expected 0 or 1 arguments".to_string(),
154+
));
155+
}
156+
};
157+
Ok(Self { limit })
99158
}
100159
}

0 commit comments

Comments
 (0)