@@ -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" => {
@@ -1252,11 +1252,23 @@ impl SessionContext {
12521252 /// (1.5 * 1024.0 * 1024.0 * 1024.0) as usize
12531253 /// );
12541254 /// ```
1255+ #[ deprecated(
1256+ since = "53.0.0" ,
1257+ note = "please use `parse_capacity_limit` function instead."
1258+ ) ]
12551259 pub fn parse_memory_limit ( limit : & str ) -> Result < usize > {
1260+ if limit. trim ( ) . is_empty ( ) {
1261+ return Err ( plan_datafusion_err ! ( "Empty limit value found!" ) ) ;
1262+ }
12561263 let ( number, unit) = limit. split_at ( limit. len ( ) - 1 ) ;
12571264 let number: f64 = number. parse ( ) . map_err ( |_| {
12581265 plan_datafusion_err ! ( "Failed to parse number from memory limit '{limit}'" )
12591266 } ) ?;
1267+ if number. is_sign_negative ( ) || number. is_infinite ( ) {
1268+ return Err ( plan_datafusion_err ! (
1269+ "Limit value should be positive finite number"
1270+ ) ) ;
1271+ }
12601272
12611273 match unit {
12621274 "K" => Ok ( ( number * 1024.0 ) as usize ) ,
@@ -1266,6 +1278,51 @@ impl SessionContext {
12661278 }
12671279 }
12681280
1281+ /// Parse capacity limit from string to number of bytes by allowing units: K, M and G.
1282+ /// Supports formats like '1.5G', '100M', '512K'
1283+ ///
1284+ /// # Examples
1285+ /// ```
1286+ /// use datafusion::execution::context::SessionContext;
1287+ ///
1288+ /// assert_eq!(
1289+ /// SessionContext::parse_capacity_limit("datafusion.runtime.memory_limit", "1M").unwrap(),
1290+ /// 1024 * 1024
1291+ /// );
1292+ /// assert_eq!(
1293+ /// SessionContext::parse_capacity_limit("datafusion.runtime.memory_limit", "1.5G").unwrap(),
1294+ /// (1.5 * 1024.0 * 1024.0 * 1024.0) as usize
1295+ /// );
1296+ /// ```
1297+ pub fn parse_capacity_limit ( config_name : & str , limit : & str ) -> Result < usize > {
1298+ if limit. trim ( ) . is_empty ( ) {
1299+ return Err ( plan_datafusion_err ! (
1300+ "Empty limit value found for '{config_name}'"
1301+ ) ) ;
1302+ }
1303+ let ( number, unit) = limit. split_at ( limit. len ( ) - 1 ) ;
1304+ let number: f64 = number. parse ( ) . map_err ( |_| {
1305+ plan_datafusion_err ! (
1306+ "Failed to parse number from '{config_name}', limit '{limit}'"
1307+ )
1308+ } ) ?;
1309+ if number. is_sign_negative ( ) || number. is_infinite ( ) {
1310+ return Err ( plan_datafusion_err ! (
1311+ "Limit value should be positive finite number for '{config_name}'"
1312+ ) ) ;
1313+ }
1314+
1315+ match unit {
1316+ "K" => Ok ( ( number * 1024.0 ) as usize ) ,
1317+ "M" => Ok ( ( number * 1024.0 * 1024.0 ) as usize ) ,
1318+ "G" => Ok ( ( number * 1024.0 * 1024.0 * 1024.0 ) as usize ) ,
1319+ _ => plan_err ! (
1320+ "Unsupported unit '{unit}' in '{config_name}', limit '{limit}'. \
1321+ Unit must be one of: 'K', 'M', 'G'"
1322+ ) ,
1323+ }
1324+ }
1325+
12691326 fn parse_duration ( duration : & str ) -> Result < Duration > {
12701327 let mut minutes = None ;
12711328 let mut seconds = None ;
@@ -2759,4 +2816,71 @@ mod tests {
27592816 assert ! ( have. is_err( ) ) ;
27602817 }
27612818 }
2819+
2820+ #[ test]
2821+ fn test_parse_memory_limit ( ) {
2822+ // Valid memory_limit
2823+ for ( limit, want) in [
2824+ ( "1.5K" , ( 1.5 * 1024.0 ) as usize ) ,
2825+ ( "2M" , ( 2f64 * 1024.0 * 1024.0 ) as usize ) ,
2826+ ( "1G" , ( 1f64 * 1024.0 * 1024.0 * 1024.0 ) as usize ) ,
2827+ ] {
2828+ #[ expect( deprecated) ]
2829+ let have = SessionContext :: parse_memory_limit ( limit) . unwrap ( ) ;
2830+ assert_eq ! ( want, have) ;
2831+ }
2832+
2833+ // Invalid memory_limit
2834+ for limit in [
2835+ "1B" ,
2836+ "1T" ,
2837+ "" ,
2838+ " " ,
2839+ "XYZG" ,
2840+ "-1G" ,
2841+ "infG" ,
2842+ "-infG" ,
2843+ "G" ,
2844+ "1024B" ,
2845+ "invalid_size" ,
2846+ ] {
2847+ #[ expect( deprecated) ]
2848+ let have = SessionContext :: parse_memory_limit ( limit) ;
2849+ assert ! ( have. is_err( ) ) ;
2850+ }
2851+ }
2852+
2853+ #[ test]
2854+ fn test_parse_capacity_limit ( ) {
2855+ const MEMORY_LIMIT : & str = "datafusion.runtime.memory_limit" ;
2856+
2857+ // Valid capacity_limit
2858+ for ( limit, want) in [
2859+ ( "1.5K" , ( 1.5 * 1024.0 ) as usize ) ,
2860+ ( "2M" , ( 2f64 * 1024.0 * 1024.0 ) as usize ) ,
2861+ ( "1G" , ( 1f64 * 1024.0 * 1024.0 * 1024.0 ) as usize ) ,
2862+ ] {
2863+ let have = SessionContext :: parse_capacity_limit ( MEMORY_LIMIT , limit) . unwrap ( ) ;
2864+ assert_eq ! ( want, have) ;
2865+ }
2866+
2867+ // Invalid capacity_limit
2868+ for limit in [
2869+ "1B" ,
2870+ "1T" ,
2871+ "" ,
2872+ " " ,
2873+ "XYZG" ,
2874+ "-1G" ,
2875+ "infG" ,
2876+ "-infG" ,
2877+ "G" ,
2878+ "1024B" ,
2879+ "invalid_size" ,
2880+ ] {
2881+ let have = SessionContext :: parse_capacity_limit ( MEMORY_LIMIT , limit) ;
2882+ assert ! ( have. is_err( ) ) ;
2883+ assert ! ( have. unwrap_err( ) . to_string( ) . contains( MEMORY_LIMIT ) ) ;
2884+ }
2885+ }
27622886}
0 commit comments