Skip to content

Commit 7a265b2

Browse files
Provide more generic API for the capacity limits
1 parent 8df75c3 commit 7a265b2

File tree

4 files changed

+55
-25
lines changed

4 files changed

+55
-25
lines changed

benchmarks/src/util/options.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ pub struct CommonOpt {
5050

5151
/// Memory limit (e.g. '100M', '1.5G'). If not specified, run all pre-defined memory limits for given query
5252
/// if there's any, otherwise run with no memory limit.
53-
#[arg(long = "memory-limit", value_parser = parse_memory_limit)]
53+
#[arg(long = "memory-limit", value_parser = parse_capacity_limit)]
5454
pub memory_limit: Option<usize>,
5555

5656
/// The amount of memory to reserve for sort spill operations. DataFusion's default value will be used
5757
/// if not specified.
58-
#[arg(long = "sort-spill-reservation-bytes", value_parser = parse_memory_limit)]
58+
#[arg(long = "sort-spill-reservation-bytes", value_parser = parse_capacity_limit)]
5959
pub sort_spill_reservation_bytes: Option<usize>,
6060

6161
/// Activate debug mode to see more details
@@ -116,20 +116,20 @@ impl CommonOpt {
116116
}
117117
}
118118

119-
/// Parse memory limit from string to number of bytes
120-
/// e.g. '1.5G', '100M' -> 1572864
121-
fn parse_memory_limit(limit: &str) -> Result<usize, String> {
119+
/// Parse capacity limit from string to number of bytes by allowing units: K, M and G.
120+
/// Supports formats like '1.5G', '100M' -> 1572864
121+
fn parse_capacity_limit(limit: &str) -> Result<usize, String> {
122122
let (number, unit) = limit.split_at(limit.len() - 1);
123123
let number: f64 = number
124124
.parse()
125-
.map_err(|_| format!("Failed to parse number from memory limit '{limit}'"))?;
125+
.map_err(|_| format!("Failed to parse number from capacity limit '{limit}'"))?;
126126

127127
match unit {
128128
"K" => Ok((number * 1024.0) as usize),
129129
"M" => Ok((number * 1024.0 * 1024.0) as usize),
130130
"G" => Ok((number * 1024.0 * 1024.0 * 1024.0) as usize),
131131
_ => Err(format!(
132-
"Unsupported unit '{unit}' in memory limit '{limit}'"
132+
"Unsupported unit '{unit}' in capacity limit '{limit}'. Unit must be one of: 'K', 'M', 'G'"
133133
)),
134134
}
135135
}
@@ -139,16 +139,16 @@ mod tests {
139139
use super::*;
140140

141141
#[test]
142-
fn test_parse_memory_limit_all() {
142+
fn test_parse_capacity_limit_all() {
143143
// Test valid inputs
144-
assert_eq!(parse_memory_limit("100K").unwrap(), 102400);
145-
assert_eq!(parse_memory_limit("1.5M").unwrap(), 1572864);
146-
assert_eq!(parse_memory_limit("2G").unwrap(), 2147483648);
144+
assert_eq!(parse_capacity_limit("100K").unwrap(), 102400);
145+
assert_eq!(parse_capacity_limit("1.5M").unwrap(), 1572864);
146+
assert_eq!(parse_capacity_limit("2G").unwrap(), 2147483648);
147147

148148
// Test invalid unit
149-
assert!(parse_memory_limit("500X").is_err());
149+
assert!(parse_capacity_limit("500X").is_err());
150150

151151
// Test invalid number
152-
assert!(parse_memory_limit("abcM").is_err());
152+
assert!(parse_capacity_limit("abcM").is_err());
153153
}
154154
}

datafusion/core/src/execution/context/mod.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,20 +1167,20 @@ impl SessionContext {
11671167
let mut builder = RuntimeEnvBuilder::from_runtime_env(state.runtime_env());
11681168
builder = match key {
11691169
"memory_limit" => {
1170-
let memory_limit = Self::parse_memory_limit(value)?;
1170+
let memory_limit = Self::parse_capacity_limit(variable, value)?;
11711171
builder.with_memory_limit(memory_limit, 1.0)
11721172
}
11731173
"max_temp_directory_size" => {
1174-
let directory_size = Self::parse_memory_limit(value)?;
1174+
let directory_size = Self::parse_capacity_limit(variable, value)?;
11751175
builder.with_max_temp_directory_size(directory_size as u64)
11761176
}
11771177
"temp_directory" => builder.with_temp_file_path(value),
11781178
"metadata_cache_limit" => {
1179-
let limit = Self::parse_memory_limit(value)?;
1179+
let limit = Self::parse_capacity_limit(variable, value)?;
11801180
builder.with_metadata_cache_limit(limit)
11811181
}
11821182
"list_files_cache_limit" => {
1183-
let limit = Self::parse_memory_limit(value)?;
1183+
let limit = Self::parse_capacity_limit(variable, value)?;
11841184
builder.with_object_list_cache_limit(limit)
11851185
}
11861186
"list_files_cache_ttl" => {
@@ -1236,33 +1236,38 @@ impl SessionContext {
12361236
Ok(())
12371237
}
12381238

1239-
/// Parse memory limit from string to number of bytes
1239+
/// Parse capacity limit from string to number of bytes by allowing units: K, M and G.
12401240
/// Supports formats like '1.5G', '100M', '512K'
12411241
///
12421242
/// # Examples
12431243
/// ```
12441244
/// use datafusion::execution::context::SessionContext;
12451245
///
12461246
/// assert_eq!(
1247-
/// SessionContext::parse_memory_limit("1M").unwrap(),
1247+
/// SessionContext::parse_capacity_limit("datafusion.runtime.memory_limit", "1M").unwrap(),
12481248
/// 1024 * 1024
12491249
/// );
12501250
/// assert_eq!(
1251-
/// SessionContext::parse_memory_limit("1.5G").unwrap(),
1251+
/// SessionContext::parse_capacity_limit("datafusion.runtime.memory_limit", "1.5G").unwrap(),
12521252
/// (1.5 * 1024.0 * 1024.0 * 1024.0) as usize
12531253
/// );
12541254
/// ```
1255-
pub fn parse_memory_limit(limit: &str) -> Result<usize> {
1255+
pub fn parse_capacity_limit(config_name: &str, limit: &str) -> Result<usize> {
12561256
let (number, unit) = limit.split_at(limit.len() - 1);
12571257
let number: f64 = number.parse().map_err(|_| {
1258-
plan_datafusion_err!("Failed to parse number from memory limit '{limit}'")
1258+
plan_datafusion_err!(
1259+
"Failed to parse number from '{config_name}', limit '{limit}'"
1260+
)
12591261
})?;
12601262

12611263
match unit {
12621264
"K" => Ok((number * 1024.0) as usize),
12631265
"M" => Ok((number * 1024.0 * 1024.0) as usize),
12641266
"G" => Ok((number * 1024.0 * 1024.0 * 1024.0) as usize),
1265-
_ => plan_err!("Unsupported unit '{unit}' in memory limit '{limit}'"),
1267+
_ => plan_err!(
1268+
"Unsupported unit '{unit}' in '{config_name}', limit '{limit}'. \
1269+
Unit must be one of: 'K', 'M', 'G'"
1270+
),
12661271
}
12671272
}
12681273

datafusion/core/tests/sql/runtime_config.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async fn test_memory_limit_enforcement() {
145145
}
146146

147147
#[tokio::test]
148-
async fn test_invalid_memory_limit() {
148+
async fn test_invalid_memory_limit_when_unit_is_invalid() {
149149
let ctx = SessionContext::new();
150150

151151
let result = ctx
@@ -154,7 +154,26 @@ async fn test_invalid_memory_limit() {
154154

155155
assert!(result.is_err());
156156
let error_message = result.unwrap_err().to_string();
157-
assert!(error_message.contains("Unsupported unit 'X'"));
157+
assert!(
158+
error_message
159+
.contains("Unsupported unit 'X' in 'datafusion.runtime.memory_limit'")
160+
&& error_message.contains("Unit must be one of: 'K', 'M', 'G'")
161+
);
162+
}
163+
164+
#[tokio::test]
165+
async fn test_invalid_memory_limit_when_limit_is_not_numeric() {
166+
let ctx = SessionContext::new();
167+
168+
let result = ctx
169+
.sql("SET datafusion.runtime.memory_limit = 'invalid_memory_limit'")
170+
.await;
171+
172+
assert!(result.is_err());
173+
let error_message = result.unwrap_err().to_string();
174+
assert!(error_message.contains(
175+
"Failed to parse number from 'datafusion.runtime.memory_limit', limit 'invalid_memory_limit'"
176+
));
158177
}
159178

160179
#[tokio::test]

datafusion/sqllogictest/test_files/set_variable.slt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,9 @@ datafusion.runtime.max_temp_directory_size
447447
datafusion.runtime.memory_limit
448448
datafusion.runtime.metadata_cache_limit
449449
datafusion.runtime.temp_directory
450+
451+
statement error DataFusion error: Error during planning: Failed to parse number from 'datafusion\.runtime\.max_temp_directory_size', limit 'invalid_size'
452+
SET datafusion.runtime.max_temp_directory_size = 'invalid_size'
453+
454+
statement error DataFusion error: Error during planning: Unsupported unit 'B' in 'datafusion\.runtime\.max_temp_directory_size', limit '1024B'\. Unit must be one of: 'K', 'M', 'G'
455+
SET datafusion.runtime.max_temp_directory_size = '1024B'

0 commit comments

Comments
 (0)