@@ -22,6 +22,7 @@ use futures::Future;
2222use object_store:: aws:: AmazonS3 ;
2323use object_store:: client:: SpawnedReqwestConnector ;
2424use tracing:: log:: * ;
25+ use typed_builder:: TypedBuilder ;
2526use url:: Url ;
2627
2728use crate :: constants;
@@ -30,6 +31,11 @@ use crate::errors::DynamoDbConfigError;
3031
3132const STORE_NAME : & str = "DeltaS3ObjectStore" ;
3233
34+ // Default values for S3StorageOptions
35+ const DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS : u64 = 15 ;
36+ const DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS : u64 = 10 ;
37+ const DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES : usize = 10 ;
38+
3339#[ derive( Clone , Default , Debug ) ]
3440pub struct S3ObjectStoreFactory { }
3541
@@ -122,21 +128,47 @@ fn is_aws(options: &HashMap<String, String>) -> bool {
122128/// Options used to configure the [S3StorageBackend].
123129///
124130/// Available options are described in [constants].
125- #[ derive( Clone , Debug ) ]
126- #[ allow ( missing_docs ) ]
131+ #[ derive( Clone , Debug , TypedBuilder ) ]
132+ #[ builder ( doc ) ]
127133pub struct S3StorageOptions {
134+ /// Whether to use virtual hosted-style requests
135+ #[ builder( default = false ) ]
128136 pub virtual_hosted_style_request : bool ,
137+ /// Locking provider to use (e.g., "dynamodb")
138+ #[ builder( default , setter( strip_option, into) ) ]
129139 pub locking_provider : Option < String > ,
140+ /// Override endpoint for DynamoDB
141+ #[ builder( default , setter( strip_option, into) ) ]
130142 pub dynamodb_endpoint : Option < String > ,
143+ /// Override region for DynamoDB
144+ #[ builder( default , setter( strip_option, into) ) ]
131145 pub dynamodb_region : Option < String > ,
146+ /// Override access key ID for DynamoDB
147+ #[ builder( default , setter( strip_option, into) ) ]
132148 pub dynamodb_access_key_id : Option < String > ,
149+ /// Override secret access key for DynamoDB
150+ #[ builder( default , setter( strip_option, into) ) ]
133151 pub dynamodb_secret_access_key : Option < String > ,
152+ /// Override session token for DynamoDB
153+ #[ builder( default , setter( strip_option, into) ) ]
134154 pub dynamodb_session_token : Option < String > ,
155+ /// Idle timeout for S3 connection pool
156+ #[ builder( default = Duration :: from_secs( DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS ) ) ]
135157 pub s3_pool_idle_timeout : Duration ,
158+ /// Idle timeout for STS connection pool
159+ #[ builder( default = Duration :: from_secs( DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS ) ) ]
136160 pub sts_pool_idle_timeout : Duration ,
161+ /// Number of retries for S3 internal server errors
162+ #[ builder( default = DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES ) ]
137163 pub s3_get_internal_server_error_retries : usize ,
164+ /// Allow unsafe rename operations
165+ #[ builder( default = false ) ]
138166 pub allow_unsafe_rename : bool ,
167+ /// Extra storage options not handled by other fields
168+ #[ builder( default ) ]
139169 pub extra_opts : HashMap < String , String > ,
170+ /// AWS SDK configuration
171+ #[ builder( default , setter( strip_option) ) ]
140172 pub sdk_config : Option < SdkConfig > ,
141173}
142174
@@ -177,15 +209,21 @@ impl S3StorageOptions {
177209 Self :: ensure_env_var ( options, constants:: AWS_WEB_IDENTITY_TOKEN_FILE ) ;
178210 Self :: ensure_env_var ( options, constants:: AWS_ROLE_ARN ) ;
179211 Self :: ensure_env_var ( options, constants:: AWS_ROLE_SESSION_NAME ) ;
180- let s3_pool_idle_timeout =
181- Self :: u64_or_default ( options, constants:: AWS_S3_POOL_IDLE_TIMEOUT_SECONDS , 15 ) ;
182- let sts_pool_idle_timeout =
183- Self :: u64_or_default ( options, constants:: AWS_STS_POOL_IDLE_TIMEOUT_SECONDS , 10 ) ;
212+ let s3_pool_idle_timeout = Self :: u64_or_default (
213+ options,
214+ constants:: AWS_S3_POOL_IDLE_TIMEOUT_SECONDS ,
215+ DEFAULT_S3_POOL_IDLE_TIMEOUT_SECONDS ,
216+ ) ;
217+ let sts_pool_idle_timeout = Self :: u64_or_default (
218+ options,
219+ constants:: AWS_STS_POOL_IDLE_TIMEOUT_SECONDS ,
220+ DEFAULT_STS_POOL_IDLE_TIMEOUT_SECONDS ,
221+ ) ;
184222
185223 let s3_get_internal_server_error_retries = Self :: u64_or_default (
186224 options,
187225 constants:: AWS_S3_GET_INTERNAL_SERVER_ERROR_RETRIES ,
188- 10 ,
226+ DEFAULT_S3_GET_INTERNAL_SERVER_ERROR_RETRIES as u64 ,
189227 ) as usize ;
190228
191229 let virtual_hosted_style_request: bool =
@@ -568,26 +606,15 @@ mod tests {
568606
569607 let options = S3StorageOptions :: try_default ( ) . unwrap ( ) ;
570608 assert_eq ! (
571- S3StorageOptions {
572- sdk_config: Some (
609+ S3StorageOptions :: builder ( )
610+ . sdk_config(
573611 SdkConfig :: builder( )
574612 . endpoint_url( "http://localhost" . to_string( ) )
575613 . region( Region :: from_static( "us-west-1" ) )
576614 . build( )
577- ) ,
578- virtual_hosted_style_request: false ,
579- locking_provider: Some ( "dynamodb" . to_string( ) ) ,
580- dynamodb_endpoint: None ,
581- dynamodb_region: None ,
582- dynamodb_access_key_id: None ,
583- dynamodb_secret_access_key: None ,
584- dynamodb_session_token: None ,
585- s3_pool_idle_timeout: Duration :: from_secs( 15 ) ,
586- sts_pool_idle_timeout: Duration :: from_secs( 10 ) ,
587- s3_get_internal_server_error_retries: 10 ,
588- extra_opts: HashMap :: new( ) ,
589- allow_unsafe_rename: false ,
590- } ,
615+ )
616+ . locking_provider( "dynamodb" )
617+ . build( ) ,
591618 options
592619 ) ;
593620 } ) ;
@@ -803,26 +830,19 @@ mod tests {
803830 . unwrap ( ) ;
804831
805832 assert_eq ! (
806- S3StorageOptions {
807- sdk_config: Some (
833+ S3StorageOptions :: builder ( )
834+ . sdk_config(
808835 SdkConfig :: builder( )
809836 . endpoint_url( "http://localhost" . to_string( ) )
810837 . region( Region :: from_static( "us-west-2" ) )
811838 . build( )
812- ) ,
813- virtual_hosted_style_request: false ,
814- locking_provider: Some ( "dynamodb" . to_string( ) ) ,
815- dynamodb_endpoint: Some ( "http://localhost:dynamodb" . to_string( ) ) ,
816- dynamodb_region: None ,
817- dynamodb_access_key_id: None ,
818- dynamodb_secret_access_key: None ,
819- dynamodb_session_token: None ,
820- s3_pool_idle_timeout: Duration :: from_secs( 1 ) ,
821- sts_pool_idle_timeout: Duration :: from_secs( 2 ) ,
822- s3_get_internal_server_error_retries: 3 ,
823- extra_opts: HashMap :: new( ) ,
824- allow_unsafe_rename: false ,
825- } ,
839+ )
840+ . locking_provider( "dynamodb" )
841+ . dynamodb_endpoint( "http://localhost:dynamodb" )
842+ . s3_pool_idle_timeout( Duration :: from_secs( 1 ) )
843+ . sts_pool_idle_timeout( Duration :: from_secs( 2 ) )
844+ . s3_get_internal_server_error_retries( 3 )
845+ . build( ) ,
826846 options
827847 ) ;
828848 } ) ;
0 commit comments