@@ -22,6 +22,8 @@ use std::{
22
22
sync:: { Arc , RwLock } ,
23
23
} ;
24
24
25
+ use arc_swap:: ArcSwap ;
26
+
25
27
use crate :: PhysicalExpr ;
26
28
use arrow:: datatypes:: { DataType , Schema } ;
27
29
use datafusion_common:: {
@@ -47,7 +49,7 @@ pub struct DynamicFilterPhysicalExpr {
47
49
/// so that when we update `current()` in subsequent iterations we can re-apply the replacements.
48
50
remapped_children : Option < Vec < Arc < dyn PhysicalExpr > > > ,
49
51
/// The source of dynamic filters.
50
- inner : Arc < RwLock < Inner > > ,
52
+ inner : Arc < ArcSwap < Inner > > ,
51
53
/// For testing purposes track the data type and nullability to make sure they don't change.
52
54
/// If they do, there's a bug in the implementation.
53
55
/// But this can have overhead in production, so it's only included in our tests.
@@ -137,7 +139,7 @@ impl DynamicFilterPhysicalExpr {
137
139
Self {
138
140
children,
139
141
remapped_children : None , // Initially no remapped children
140
- inner : Arc :: new ( RwLock :: new ( Inner :: new ( inner) ) ) ,
142
+ inner : Arc :: new ( ArcSwap :: from_pointee ( Inner :: new ( inner) ) ) ,
141
143
data_type : Arc :: new ( RwLock :: new ( None ) ) ,
142
144
nullable : Arc :: new ( RwLock :: new ( None ) ) ,
143
145
}
@@ -176,17 +178,8 @@ impl DynamicFilterPhysicalExpr {
176
178
/// This will return the current expression with any children
177
179
/// remapped to match calls to [`PhysicalExpr::with_new_children`].
178
180
pub fn current ( & self ) -> Result < Arc < dyn PhysicalExpr > > {
179
- let inner = Arc :: clone (
180
- & self
181
- . inner
182
- . read ( )
183
- . map_err ( |_| {
184
- datafusion_common:: DataFusionError :: Execution (
185
- "Failed to acquire read lock for inner" . to_string ( ) ,
186
- )
187
- } ) ?
188
- . expr ,
189
- ) ;
181
+ let inner_ref = self . inner . load ( ) ;
182
+ let inner = Arc :: clone ( & inner_ref. expr ) ;
190
183
let inner =
191
184
Self :: remap_children ( & self . children , self . remapped_children . as_ref ( ) , inner) ?;
192
185
Ok ( inner)
@@ -199,11 +192,6 @@ impl DynamicFilterPhysicalExpr {
199
192
/// - When we've computed the probe side's hash table in a HashJoinExec
200
193
/// - After every batch is processed if we update the TopK heap in a SortExec using a TopK approach.
201
194
pub fn update ( & self , new_expr : Arc < dyn PhysicalExpr > ) -> Result < ( ) > {
202
- let mut current = self . inner . write ( ) . map_err ( |_| {
203
- datafusion_common:: DataFusionError :: Execution (
204
- "Failed to acquire write lock for inner" . to_string ( ) ,
205
- )
206
- } ) ?;
207
195
// Remap the children of the new expression to match the original children
208
196
// We still do this again in `current()` but doing it preventively here
209
197
// reduces the work needed in some cases if `current()` is called multiple times
@@ -213,10 +201,14 @@ impl DynamicFilterPhysicalExpr {
213
201
self . remapped_children . as_ref ( ) ,
214
202
new_expr,
215
203
) ?;
216
- // Update the inner expression to the new expression.
217
- current. expr = new_expr;
218
- // Increment the generation to indicate that the expression has changed.
219
- current. generation += 1 ;
204
+
205
+ // Load the current inner, increment generation, and store the new one
206
+ let current = self . inner . load ( ) ;
207
+ let new_inner = Inner {
208
+ generation : current. generation + 1 ,
209
+ expr : new_expr,
210
+ } ;
211
+ self . inner . store ( Arc :: new ( new_inner) ) ;
220
212
Ok ( ( ) )
221
213
}
222
214
}
@@ -324,10 +316,7 @@ impl PhysicalExpr for DynamicFilterPhysicalExpr {
324
316
325
317
fn snapshot_generation ( & self ) -> u64 {
326
318
// Return the current generation of the expression.
327
- self . inner
328
- . read ( )
329
- . expect ( "Failed to acquire read lock for inner" )
330
- . generation
319
+ self . inner . load ( ) . generation
331
320
}
332
321
}
333
322
0 commit comments