@@ -12,6 +12,7 @@ use crate::actions::get_log_add_schema;
1212use crate :: engine_data:: { GetData , RowVisitor , TypedGetData as _} ;
1313use crate :: expressions:: { column_name, ColumnName , Expression , ExpressionRef , PredicateRef } ;
1414use crate :: kernel_predicates:: { DefaultKernelPredicateEvaluator , KernelPredicateEvaluator as _} ;
15+ use crate :: log_replay:: deduplicator:: Deduplicator ;
1516use crate :: log_replay:: { ActionsBatch , FileActionDeduplicator , FileActionKey , LogReplayProcessor } ;
1617use crate :: scan:: Scalar ;
1718use crate :: schema:: ToSchema as _;
@@ -80,6 +81,15 @@ pub(crate) struct ScanLogReplayProcessor {
8081}
8182
8283impl ScanLogReplayProcessor {
84+ // These index positions correspond to the order of columns defined in
85+ // `selected_column_names_and_types()`
86+ const ADD_PATH_INDEX : usize = 0 ; // Position of "add.path" in getters
87+ const ADD_PARTITION_VALUES_INDEX : usize = 1 ; // Position of "add.partitionValues" in getters
88+ const ADD_DV_START_INDEX : usize = 2 ; // Start position of add deletion vector columns
89+ const BASE_ROW_ID_INDEX : usize = 5 ; // Position of add.baseRowId in getters
90+ const REMOVE_PATH_INDEX : usize = 6 ; // Position of "remove.path" in getters
91+ const REMOVE_DV_START_INDEX : usize = 7 ; // Start position of remove deletion vector columns
92+
8393 /// Create a new [`ScanLogReplayProcessor`] instance
8494 pub ( crate ) fn new ( engine : & dyn Engine , state_info : Arc < StateInfo > ) -> DeltaResult < Self > {
8595 Self :: new_with_seen_files ( engine, state_info, Default :: default ( ) )
@@ -226,40 +236,23 @@ impl ScanLogReplayProcessor {
226236/// replay visits actions newest-first, so once we've seen a file action for a given (path, dvId)
227237/// pair, we should ignore all subsequent (older) actions for that same (path, dvId) pair. If the
228238/// first action for a given file is a remove, then that file does not show up in the result at all.
229- struct AddRemoveDedupVisitor < ' seen > {
230- deduplicator : FileActionDeduplicator < ' seen > ,
239+ struct AddRemoveDedupVisitor < D : Deduplicator > {
240+ deduplicator : D ,
231241 selection_vector : Vec < bool > ,
232242 state_info : Arc < StateInfo > ,
233243 partition_filter : Option < PredicateRef > ,
234244 row_transform_exprs : Vec < Option < ExpressionRef > > ,
235245}
236246
237- impl AddRemoveDedupVisitor < ' _ > {
238- // These index positions correspond to the order of columns defined in
239- // `selected_column_names_and_types()`
240- const ADD_PATH_INDEX : usize = 0 ; // Position of "add.path" in getters
241- const ADD_PARTITION_VALUES_INDEX : usize = 1 ; // Position of "add.partitionValues" in getters
242- const ADD_DV_START_INDEX : usize = 2 ; // Start position of add deletion vector columns
243- const BASE_ROW_ID_INDEX : usize = 5 ; // Position of add.baseRowId in getters
244- const REMOVE_PATH_INDEX : usize = 6 ; // Position of "remove.path" in getters
245- const REMOVE_DV_START_INDEX : usize = 7 ; // Start position of remove deletion vector columns
246-
247+ impl < D : Deduplicator > AddRemoveDedupVisitor < D > {
247248 fn new (
248- seen : & mut HashSet < FileActionKey > ,
249+ deduplicator : D ,
249250 selection_vector : Vec < bool > ,
250251 state_info : Arc < StateInfo > ,
251252 partition_filter : Option < PredicateRef > ,
252- is_log_batch : bool ,
253- ) -> AddRemoveDedupVisitor < ' _ > {
253+ ) -> AddRemoveDedupVisitor < D > {
254254 AddRemoveDedupVisitor {
255- deduplicator : FileActionDeduplicator :: new (
256- seen,
257- is_log_batch,
258- Self :: ADD_PATH_INDEX ,
259- Self :: REMOVE_PATH_INDEX ,
260- Self :: ADD_DV_START_INDEX ,
261- Self :: REMOVE_DV_START_INDEX ,
262- ) ,
255+ deduplicator,
263256 selection_vector,
264257 state_info,
265258 partition_filter,
@@ -311,8 +304,8 @@ impl AddRemoveDedupVisitor<'_> {
311304 // encounter if the table's schema was replaced after the most recent checkpoint.
312305 let partition_values = match & self . state_info . transform_spec {
313306 Some ( transform) if is_add => {
314- let partition_values =
315- getters [ Self :: ADD_PARTITION_VALUES_INDEX ] . get ( i, "add.partitionValues" ) ?;
307+ let partition_values = getters [ ScanLogReplayProcessor :: ADD_PARTITION_VALUES_INDEX ]
308+ . get ( i, "add.partitionValues" ) ?;
316309 let partition_values = parse_partition_values (
317310 & self . state_info . logical_schema ,
318311 transform,
@@ -332,7 +325,7 @@ impl AddRemoveDedupVisitor<'_> {
332325 return Ok ( false ) ;
333326 }
334327 let base_row_id: Option < i64 > =
335- getters[ Self :: BASE_ROW_ID_INDEX ] . get_opt ( i, "add.baseRowId" ) ?;
328+ getters[ ScanLogReplayProcessor :: BASE_ROW_ID_INDEX ] . get_opt ( i, "add.baseRowId" ) ?;
336329 let transform = self
337330 . state_info
338331 . transform_spec
@@ -355,7 +348,7 @@ impl AddRemoveDedupVisitor<'_> {
355348 }
356349}
357350
358- impl RowVisitor for AddRemoveDedupVisitor < ' _ > {
351+ impl < D : Deduplicator > RowVisitor for AddRemoveDedupVisitor < D > {
359352 fn selected_column_names_and_types ( & self ) -> ( & ' static [ ColumnName ] , & ' static [ DataType ] ) {
360353 // NOTE: The visitor assumes a schema with adds first and removes optionally afterward.
361354 static NAMES_AND_TYPES : LazyLock < ColumnNamesAndTypes > = LazyLock :: new ( || {
@@ -501,12 +494,19 @@ impl LogReplayProcessor for ScanLogReplayProcessor {
501494 let selection_vector = self . build_selection_vector ( actions. as_ref ( ) ) ?;
502495 assert_eq ! ( selection_vector. len( ) , actions. len( ) ) ;
503496
504- let mut visitor = AddRemoveDedupVisitor :: new (
497+ let deduplicator = FileActionDeduplicator :: new (
505498 & mut self . seen_file_keys ,
499+ is_log_batch,
500+ Self :: ADD_PATH_INDEX ,
501+ Self :: REMOVE_PATH_INDEX ,
502+ Self :: ADD_DV_START_INDEX ,
503+ Self :: REMOVE_DV_START_INDEX ,
504+ ) ;
505+ let mut visitor = AddRemoveDedupVisitor :: new (
506+ deduplicator,
506507 selection_vector,
507508 self . state_info . clone ( ) ,
508509 self . partition_filter . clone ( ) ,
509- is_log_batch,
510510 ) ;
511511 visitor. visit_rows_of ( actions. as_ref ( ) ) ?;
512512
0 commit comments