@@ -859,6 +859,7 @@ public ColumnData resolve(Object[] cells, int lb, int ub)
859859 private final boolean isSorted ;
860860 private BTree .Builder <Cell <?>> cells_ ;
861861 private boolean hasComplex = false ;
862+ private long minCellDeletionTime = Cell .MAX_DELETION_TIME ;
862863
863864 // For complex column at index i of 'columns', we store at complexDeletions[i] its complex deletion.
864865
@@ -888,6 +889,7 @@ protected Builder(Builder builder)
888889 cells_ = builder .cells_ == null ? null : builder .cells_ .copy ();
889890 isSorted = builder .isSorted ;
890891 hasComplex = builder .hasComplex ;
892+ minCellDeletionTime = builder .minCellDeletionTime ;
891893 }
892894
893895 @ Override
@@ -919,6 +921,7 @@ protected void reset()
919921 this .deletion = Deletion .LIVE ;
920922 this .cells_ .reuse ();
921923 this .hasComplex = false ;
924+ this .minCellDeletionTime = Cell .MAX_DELETION_TIME ;
922925 if (pool != null )
923926 {
924927 pool .offer (this );
@@ -951,12 +954,14 @@ public void addCell(Cell<?> cell)
951954
952955 getCells ().add (cell );
953956 hasComplex |= cell .column .isComplex ();
957+ minCellDeletionTime = Math .min (minCellDeletionTime , minDeletionTime (cell ));
954958 }
955959
956960 public void addComplexDeletion (ColumnMetadata column , DeletionTime complexDeletion )
957961 {
958962 getCells ().add (new ComplexColumnDeletion (column , complexDeletion ));
959963 hasComplex = true ;
964+ minCellDeletionTime = Math .min (minCellDeletionTime , minDeletionTime (complexDeletion ));
960965 }
961966
962967 public Row build ()
@@ -965,14 +970,33 @@ public Row build()
965970 getCells ().sort ();
966971 // we can avoid resolving if we're sorted and have no complex values
967972 // (because we'll only have unique simple cells, which are already in their final condition)
968- if (!isSorted | hasComplex )
973+ boolean resolved = !isSorted | hasComplex ;
974+ if (resolved )
969975 getCells ().resolve (CellResolver .instance );
970976 Object [] btree = getCells ().build ();
971977
972978 if (deletion .isShadowedBy (primaryKeyLivenessInfo ))
973979 deletion = Deletion .LIVE ;
974980
975- long minDeletionTime = minDeletionTime (btree , primaryKeyLivenessInfo , deletion .time ());
981+ long minDeletionTime ;
982+ // Use the incrementally tracked min when it is guaranteed to be exact:
983+ // - !resolved: CellResolver did not run, so no cells were merged or shadowed.
984+ // - minCellDeletionTime == Cell.MAX_DELETION_TIME: no cell or complex deletion contributed
985+ // any deletion info, so reconciliation in CellResolver cannot have made the tracked min
986+ // pessimistic (every cell has localDeletionTime == NO_DELETION_TIME).
987+ // Otherwise fall back to the exact O(N) computation, since reconciliation between expiring
988+ // cells with equal timestamps may keep a cell whose localDeletionTime is larger than what
989+ // we tracked.
990+ if (!resolved || minCellDeletionTime == Cell .MAX_DELETION_TIME )
991+ {
992+ minDeletionTime = Math .min (minCellDeletionTime ,
993+ Math .min (minDeletionTime (primaryKeyLivenessInfo ),
994+ minDeletionTime (deletion .time ())));
995+ }
996+ else
997+ {
998+ minDeletionTime = minDeletionTime (btree , primaryKeyLivenessInfo , deletion .time ());
999+ }
9761000 Row row = BTreeRow .create (clustering , primaryKeyLivenessInfo , deletion , btree , minDeletionTime );
9771001 reset ();
9781002 return row ;
0 commit comments