@@ -130,6 +130,34 @@ impl MountTable {
130130 }
131131}
132132
133+ /// Holds either a [Runtime] or a [Handle] to an existing runtime for IO tasks
134+ #[ derive( Debug ) ]
135+ pub enum IORuntime {
136+ Runtime ( Runtime ) ,
137+ Handle ( Handle ) ,
138+ }
139+
140+ impl From < Runtime > for IORuntime {
141+ fn from ( value : Runtime ) -> Self {
142+ Self :: Runtime ( value)
143+ }
144+ }
145+
146+ impl From < Handle > for IORuntime {
147+ fn from ( value : Handle ) -> Self {
148+ Self :: Handle ( value)
149+ }
150+ }
151+
152+ impl IORuntime {
153+ fn handle ( & self ) -> Handle {
154+ match self {
155+ Self :: Runtime ( runtime) => runtime. handle ( ) . clone ( ) ,
156+ Self :: Handle ( handle) => handle. clone ( ) ,
157+ }
158+ }
159+ }
160+
133161/// Builds a new [Client] instance. By default, configs will be loaded from the default config directories with the following precedence:
134162/// - If the `HADOOP_CONF_DIR` environment variable is defined, configs will be loaded from `${HADOOP_CONF_DIR}/{core,hdfs}-site.xml`
135163/// - If the `HADOOP_HOME` environment variable is defined, configs will be loaded from `${HADOOP_HOME}/etc/hadoop/{core,hdfs}-site.xml`
@@ -170,7 +198,7 @@ impl MountTable {
170198pub struct ClientBuilder {
171199 url : Option < String > ,
172200 config : HashMap < String , String > ,
173- runtime : Option < Runtime > ,
201+ runtime : Option < IORuntime > ,
174202}
175203
176204impl ClientBuilder {
@@ -197,9 +225,10 @@ impl ClientBuilder {
197225 self
198226 }
199227
200- /// Use a dedicated tokio runtime for spawned tasks and IO operations
201- pub fn with_io_runtime ( mut self , runtime : Runtime ) -> Self {
202- self . runtime = Some ( runtime) ;
228+ /// Use a dedicated tokio runtime for spawned tasks and IO operations. Can either take ownership of a whole [Runtime]
229+ /// or take a [Handle] to an externally owned runtime.
230+ pub fn with_io_runtime ( mut self , runtime : impl Into < IORuntime > ) -> Self {
231+ self . runtime = Some ( runtime. into ( ) ) ;
203232 self
204233 }
205234
@@ -218,12 +247,12 @@ impl ClientBuilder {
218247
219248#[ derive( Clone , Debug ) ]
220249enum RuntimeHolder {
221- Custom ( Arc < Runtime > ) ,
250+ Custom ( Arc < IORuntime > ) ,
222251 Default ( Arc < OnceLock < Runtime > > ) ,
223252}
224253
225254impl RuntimeHolder {
226- fn new ( rt : Option < Runtime > ) -> Self {
255+ fn new ( rt : Option < IORuntime > ) -> Self {
227256 if let Some ( rt) = rt {
228257 Self :: Custom ( Arc :: new ( rt) )
229258 } else {
@@ -287,7 +316,7 @@ impl Client {
287316 Ok ( Url :: parse ( url) ?)
288317 }
289318
290- fn build ( url : & Url , config : Configuration , rt : Option < Runtime > ) -> Result < Self > {
319+ fn build ( url : & Url , config : Configuration , rt : Option < IORuntime > ) -> Result < Self > {
291320 let resolved_url = if !url. has_host ( ) {
292321 let default_url = Self :: default_fs ( & config) ?;
293322 if url. scheme ( ) != default_url. scheme ( ) || !default_url. has_host ( ) {
@@ -1025,4 +1054,20 @@ mod test {
10251054 assert_eq ! ( link. viewfs_path, "/mount3/nested" ) ;
10261055 assert_eq ! ( resolved, "/path3/file" ) ;
10271056 }
1057+
1058+ #[ test]
1059+ fn test_io_runtime ( ) {
1060+ assert ! ( ClientBuilder :: new( )
1061+ . with_url( "hdfs://127.0.0.1:9000" )
1062+ . with_io_runtime( Runtime :: new( ) . unwrap( ) )
1063+ . build( )
1064+ . is_ok( ) ) ;
1065+
1066+ let rt = Runtime :: new ( ) . unwrap ( ) ;
1067+ assert ! ( ClientBuilder :: new( )
1068+ . with_url( "hdfs://127.0.0.1:9000" )
1069+ . with_io_runtime( rt. handle( ) . clone( ) )
1070+ . build( )
1071+ . is_ok( ) ) ;
1072+ }
10281073}
0 commit comments