@@ -56,6 +56,10 @@ use crate::task_estimator::DataSourceExecPartitionEstimator;
5656type CatalogProviderFactory = Arc < dyn Fn ( ) -> Arc < dyn CatalogProvider > + Send + Sync > ;
5757type SchemaProviderFactory = Arc < dyn Fn ( ) -> Arc < dyn SchemaProvider > + Send + Sync > ;
5858
59+ /// Default per-node DataFusion cache budget for file-embedded metadata such
60+ /// as Parquet footers and page indexes.
61+ pub const DEFAULT_FILE_METADATA_CACHE_LIMIT_BYTES : usize = 4usize * 1024 * 1024 * 1024 ;
62+
5963#[ derive( Clone ) ]
6064pub ( crate ) struct CatalogRegistration {
6165 name : String ,
@@ -80,6 +84,7 @@ pub struct DataFusionSessionBuilder {
8084 task_estimator : Arc < dyn TaskEstimator + Send + Sync > ,
8185 memory_pool : Option < Arc < dyn MemoryPool > > ,
8286 object_store_registry : Option < Arc < dyn ObjectStoreRegistry > > ,
87+ file_metadata_cache_limit_bytes : usize ,
8388 runtime : Arc < RuntimeEnv > ,
8489}
8590
@@ -91,6 +96,10 @@ impl std::fmt::Debug for DataFusionSessionBuilder {
9196 . field ( "num_catalogs" , & self . catalog_registrations . len ( ) )
9297 . field ( "num_schemas" , & self . schema_registrations . len ( ) )
9398 . field ( "distributed" , & self . worker_resolver . is_some ( ) )
99+ . field (
100+ "file_metadata_cache_limit_bytes" ,
101+ & self . file_metadata_cache_limit_bytes ,
102+ )
94103 . finish ( )
95104 }
96105}
@@ -103,6 +112,10 @@ impl Default for DataFusionSessionBuilder {
103112
104113impl DataFusionSessionBuilder {
105114 pub fn new ( ) -> Self {
115+ let runtime = RuntimeEnvBuilder :: new ( )
116+ . with_metadata_cache_limit ( DEFAULT_FILE_METADATA_CACHE_LIMIT_BYTES )
117+ . build_arc ( )
118+ . expect ( "default DataFusion runtime should build" ) ;
106119 Self {
107120 runtime_plugins : Vec :: new ( ) ,
108121 substrait_extensions : Vec :: new ( ) ,
@@ -112,12 +125,14 @@ impl DataFusionSessionBuilder {
112125 task_estimator : Arc :: new ( DataSourceExecPartitionEstimator ) ,
113126 memory_pool : None ,
114127 object_store_registry : None ,
115- runtime : Arc :: new ( RuntimeEnv :: default ( ) ) ,
128+ file_metadata_cache_limit_bytes : DEFAULT_FILE_METADATA_CACHE_LIMIT_BYTES ,
129+ runtime,
116130 }
117131 }
118132
119133 fn rebuild_runtime ( & mut self ) -> DFResult < ( ) > {
120- let mut builder = RuntimeEnvBuilder :: new ( ) ;
134+ let mut builder = RuntimeEnvBuilder :: new ( )
135+ . with_metadata_cache_limit ( self . file_metadata_cache_limit_bytes ) ;
121136 if let Some ( memory_pool) = & self . memory_pool {
122137 builder = builder. with_memory_pool ( Arc :: clone ( memory_pool) ) ;
123138 }
@@ -176,6 +191,12 @@ impl DataFusionSessionBuilder {
176191 Ok ( self )
177192 }
178193
194+ pub fn with_file_metadata_cache_limit ( mut self , bytes : usize ) -> DFResult < Self > {
195+ self . file_metadata_cache_limit_bytes = bytes;
196+ self . rebuild_runtime ( ) ?;
197+ Ok ( self )
198+ }
199+
179200 pub fn with_object_store_registry (
180201 mut self ,
181202 registry : Arc < dyn ObjectStoreRegistry > ,
@@ -411,6 +432,21 @@ mod tests {
411432 }
412433 }
413434
435+ #[ test]
436+ fn file_metadata_cache_limit_defaults_to_four_gib_and_can_be_overridden ( ) {
437+ let builder = DataFusionSessionBuilder :: new ( ) ;
438+ assert_eq ! (
439+ builder. runtime( ) . cache_manager. get_metadata_cache_limit( ) ,
440+ DEFAULT_FILE_METADATA_CACHE_LIMIT_BYTES
441+ ) ;
442+
443+ let builder = builder. with_file_metadata_cache_limit ( 8 * 1024 ) . unwrap ( ) ;
444+ assert_eq ! (
445+ builder. runtime( ) . cache_manager. get_metadata_cache_limit( ) ,
446+ 8 * 1024
447+ ) ;
448+ }
449+
414450 #[ test]
415451 fn runtime_settings_compose_and_reinitialize_sources ( ) {
416452 let source_url = Url :: parse ( "test://source" ) . unwrap ( ) ;
@@ -442,6 +478,10 @@ mod tests {
442478 . and_then( |entry| entry. value) ,
443479 Some ( "2K" . to_string( ) )
444480 ) ;
481+ assert_eq ! (
482+ builder. runtime( ) . cache_manager. get_metadata_cache_limit( ) ,
483+ DEFAULT_FILE_METADATA_CACHE_LIMIT_BYTES
484+ ) ;
445485 assert ! (
446486 builder
447487 . runtime( )
0 commit comments