7
7
//! Specific pieces of configuration must implement the `TryUpdateKey` trait which
8
8
//! defines how to update internal fields based on key-value pairs.
9
9
use std:: collections:: HashMap ;
10
+ use std:: sync:: Arc ;
10
11
11
12
use :: object_store:: RetryConfig ;
12
13
use object_store:: { path:: Path , prefix:: PrefixStore , ObjectStore , ObjectStoreScheme } ;
13
14
15
+ use super :: storage:: file_cache:: { self , FileCacheConfig } ;
14
16
use super :: storage:: LimitConfig ;
15
17
use super :: { storage:: runtime:: RuntimeConfig , IORuntime } ;
16
18
use crate :: { DeltaResult , DeltaTableError } ;
@@ -101,6 +103,11 @@ pub struct StorageConfig {
101
103
/// Configuration to limit the number of concurrent requests to the object store.
102
104
pub limit : Option < LimitConfig > ,
103
105
106
+ /// File cache configuration.
107
+ ///
108
+ /// Configuration to enable file cache for the Delta Log Store.
109
+ pub file_cache : Option < FileCacheConfig > ,
110
+
104
111
/// Properties that are not recognized by the storage configuration.
105
112
///
106
113
/// These properties are ignored by the storage configuration and can be used for custom purposes.
@@ -119,12 +126,27 @@ impl StorageConfig {
119
126
/// Depending on the configuration, the following layers may be added:
120
127
/// - Retry layer: Adds retry logic to the object store.
121
128
/// - Limit layer: Limits the number of concurrent requests to the object store.
129
+ /// - File cache layer: Adds a file cache to the object store.
122
130
pub fn decorate_store < T : ObjectStore + Clone > (
123
131
& self ,
124
132
store : T ,
125
133
table_root : & url:: Url ,
126
134
) -> DeltaResult < Box < dyn ObjectStore > > {
127
- let inner = Self :: decorate_prefix ( store, table_root) ?;
135
+ let inner = self . decorate_root_store ( store) ?;
136
+ let inner = Self :: decorate_prefix ( inner, table_root) ?;
137
+ Ok ( inner)
138
+ }
139
+
140
+ /// Wraps an object store with additional layers of functionality without prefix.
141
+ pub ( crate ) fn decorate_root_store < T : ObjectStore > (
142
+ & self ,
143
+ store : T ,
144
+ ) -> DeltaResult < Box < dyn ObjectStore > > {
145
+ let inner = if let Some ( file_cache) = self . file_cache . as_ref ( ) {
146
+ file_cache:: decorate_store ( Arc :: new ( store) , file_cache) ?
147
+ } else {
148
+ Box :: new ( store)
149
+ } ;
128
150
Ok ( inner)
129
151
}
130
152
@@ -225,6 +247,11 @@ impl StorageConfig {
225
247
remainder
226
248
} ;
227
249
250
+ let result = ParseResult :: < FileCacheConfig > :: from_iter ( remainder) ;
251
+ result. raise_errors ( ) ?;
252
+ props. file_cache = ( !result. is_default ) . then_some ( result. config ) ;
253
+ let remainder = result. unparsed ;
254
+
228
255
props. unknown_properties = remainder;
229
256
Ok ( props)
230
257
}
@@ -296,6 +323,7 @@ pub fn str_is_truthy(val: &str) -> bool {
296
323
297
324
#[ cfg( test) ]
298
325
mod tests {
326
+ use super :: FileCacheConfig ;
299
327
use maplit:: hashmap;
300
328
use object_store:: RetryConfig ;
301
329
use std:: time:: Duration ;
@@ -318,4 +346,36 @@ mod tests {
318
346
assert_eq ! ( retry_config. backoff. max_backoff, Duration :: from_secs( 3600 ) ) ;
319
347
assert_eq ! ( retry_config. backoff. base, 50_f64 ) ;
320
348
}
349
+
350
+ #[ test]
351
+ fn test_file_cache_config_from_options ( ) {
352
+ let options = hashmap ! {
353
+ "file_cache_path" . to_string( ) => "/tmp/file_cache" . to_string( ) ,
354
+ } ;
355
+
356
+ let ( file_cache_config, remainder) : ( FileCacheConfig , _ ) =
357
+ super :: try_parse_impl ( options) . unwrap ( ) ;
358
+ assert ! ( remainder. is_empty( ) ) ;
359
+
360
+ assert_eq ! ( file_cache_config. path, "/tmp/file_cache" ) ;
361
+ assert ! ( file_cache_config. last_checkpoint_valid_duration. is_none( ) ) ;
362
+ }
363
+
364
+ #[ test]
365
+ fn test_file_cache_config_from_options_with_last_checkpoint_valid_duration ( ) {
366
+ let options = hashmap ! {
367
+ "file_cache_path" . to_string( ) => "/tmp/file_cache" . to_string( ) ,
368
+ "file_cache_last_checkpoint_valid_duration" . to_string( ) => "1h" . to_string( ) ,
369
+ } ;
370
+
371
+ let ( file_cache_config, remainder) : ( FileCacheConfig , _ ) =
372
+ super :: try_parse_impl ( options) . unwrap ( ) ;
373
+ assert ! ( remainder. is_empty( ) ) ;
374
+
375
+ assert_eq ! ( file_cache_config. path, "/tmp/file_cache" ) ;
376
+ assert_eq ! (
377
+ file_cache_config. last_checkpoint_valid_duration,
378
+ Some ( Duration :: from_secs( 3600 ) )
379
+ ) ;
380
+ }
321
381
}
0 commit comments