@@ -1364,7 +1364,20 @@ private List<Dictionary<string, object>> ScanRowsWithSimdAndFilterStale(byte[] d
13641364 dataSpan . Slice ( filePosition , 4 ) ) ;
13651365
13661366 const int MaxRecordSize = 1_000_000_000 ;
1367- if ( recordLength < 0 || recordLength > MaxRecordSize )
1367+ if ( recordLength < 0 )
1368+ {
1369+ // Tombstoned (deleted) record: the prefix stores the negative slot size to skip.
1370+ int slotSize = - recordLength ;
1371+ if ( slotSize < 4 )
1372+ {
1373+ break ;
1374+ }
1375+
1376+ filePosition += slotSize ;
1377+ continue ;
1378+ }
1379+
1380+ if ( recordLength > MaxRecordSize )
13681381 {
13691382 break ;
13701383 }
@@ -2586,9 +2599,10 @@ private bool HasExplicitNamedIndex(string column)
25862599 foreach ( var ( storagePosition , _) in recordsToDelete )
25872600 engine . Delete ( Name , storagePosition ) ;
25882601 }
2589- else
2602+ else if ( StorageMode != StorageMode . Columnar )
25902603 {
2591- // Track Columnar logical deletes so flush-time compaction makes them durable.
2604+ // Legacy logical-delete accounting (Columnar deletes are tracked in the branch below,
2605+ // which decides between an immediate durable tombstone and deferred flush compaction).
25922606 Interlocked . Add ( ref _pendingLogicalDeletes , recordsToDelete . Count ) ;
25932607 }
25942608
@@ -2639,6 +2653,20 @@ private bool HasExplicitNamedIndex(string column)
26392653 }
26402654 }
26412655
2656+ if ( this . storage is { IsInTransaction : true } )
2657+ {
2658+ // Transactional delete: writing the tombstone now would survive a rollback that
2659+ // restores the row in the PK index, so defer the physical removal to the post-commit
2660+ // flush compaction (rollback-safe: that rewrite is driven by the CURRENT PK, which
2661+ // still contains the row after a rollback).
2662+ Interlocked . Add ( ref _pendingLogicalDeletes , recordsToDelete . Count ) ;
2663+ }
2664+ else
2665+ {
2666+ // Durable DELETE: physically mark the removed records so a reopen skips them.
2667+ TombstoneDeletedPositions ( positions ) ;
2668+ }
2669+
26422670 TryAutoCompact ( ) ;
26432671 }
26442672
@@ -3184,8 +3212,19 @@ this.storage is null ||
31843212 hashIdx . RemoveBatchKeys ( decoded , positions ) ;
31853213 }
31863214
3215+ if ( this . storage is { IsInTransaction : true } )
3216+ {
3217+ // Transactional delete: defer physical removal to the post-commit flush compaction
3218+ // (see DeleteRecordsCore — a tombstone would survive a rollback that restores the row).
3219+ Interlocked . Add ( ref _pendingLogicalDeletes , count ) ;
3220+ }
3221+ else
3222+ {
3223+ // Durable DELETE: physically mark the removed records so a reopen skips them.
3224+ TombstoneDeletedPositions ( positions ) ;
3225+ }
3226+
31873227 Interlocked . Add ( ref _cachedRowCount , - count ) ;
3188- Interlocked . Add ( ref _pendingLogicalDeletes , count ) ;
31893228 Interlocked . Increment ( ref _bulkContiguousDeleteBatches ) ;
31903229 return true ;
31913230 }
0 commit comments