Skip to content

perf: apply DELETE tombstones at COMMIT for transactional deletes (no flush rewrite) - #368

Merged
MPCoreDeveloper merged 1 commit into
masterfrom
perf/commit-time-tombstones
Sep 3, 2026
Merged

perf: apply DELETE tombstones at COMMIT for transactional deletes (no flush rewrite)#368
MPCoreDeveloper merged 1 commit into
masterfrom
perf/commit-time-tombstones

Conversation

@MPCoreDeveloper

Copy link
Copy Markdown
Owner

Stack

Waarom

Stap-0-profiling (env-gestuurde op/flush-splitsing + Database.Flush-fasebreakdown) toonde: ExecuteBatchSQL draait elke batch in een storage-transactie, dus batch-DELETE nam de rollback-veilige deferral (_pendingLogicalDeletes) en db.Flush() deed nog steeds de full-file CompactPendingDeletes-rewrite (~0,5–0,7 s; DELETE ~12–16K ops/s). Tombstones werden in de benchmark dus nooit geschreven.

Fix

  • IStorage.BufferTombstoneForCommit (default no-op) + Storage-implementatie: buffert per bestand de fysieke offsets van in-transactie-deletes.
  • ApplyBufferedTombstones() draait in FlushBufferedAppendsAndOverwrites() (de commit-path) de buffered appends op schijf staan → markers in-place, O(delete), geen rewrite. Offsets van rijen die in dezelfde transactie zijn geïnsereerd én verwijderd zijn dan geldig.
  • Rollback (ClearBufferedAppends) gooit de buffer weg → rij blijft behouden.
  • DeleteRecordsCore + de contiguous FW-bulk-path bufferen de offsets i.p.v. _pendingLogicalDeletes te verhogen → flush-compactie is volledig van het batch-DELETE-pad af.

Metingen (zelfde machine, Release, 10K deletes op ~100K rijen)

Harness voor na
comparative SQL 0,82 s / ~12K ops/s 0,24 s / ~41K ops/s
comparative Direct 0,63 s / ~16K ops/s 0,17 s / ~58K ops/s
--pk legacy (flush rewrite) 0,16 s / ~62K ops/s
--pk fixed-width (flush rewrite) 0,13 s / ~78K ops/s

Validatie

  • Nieuwe regressie BatchDelete_CommitTimeTombstones_SurviveReopenWithoutExplicitFlush — deletes overleven reopen zonder expliciete Flush na ExecuteBatchSQL.
  • Volledige SharpCoreDB.Tests (Debug + Release/CI-filter) en de CI-suites (VectorSearch, EFCore, Linq2DB): EXIT=0.

… flush rewrite)

Stap-0 profiling showed batch DELETE (ExecuteBatchSQL wraps every batch in a storage transaction) was NOT using the tombstone path: the rollback-safe deferral only counted _pendingLogicalDeletes, so db.Flush() still ran the #366 full-file CompactPendingDeletes rewrite (~0.5-0.7s; DELETE stuck at ~12-16K ops/s).

- IStorage.BufferTombstoneForCommit (default no-op) + Storage implementation: buffered offsets per file, applied as in-place negative-prefix markers by ApplyBufferedTombstones() inside FlushBufferedAppendsAndOverwrites() (the commit path) AFTER buffered appends are on disk; rollback discards the buffer via ClearBufferedAppends().

- DeleteRecordsCore + the contiguous FW bulk path now buffer the deleted offsets when IsInTransaction instead of incrementing _pendingLogicalDeletes, so the flush-time full-file rewrite is off the batch-DELETE path entirely.

- Regression: batch DELETE survives reopen even WITHOUT an explicit Flush after ExecuteBatchSQL (commit already tombstoned the rows).

Measured (same machine, Release, comparative harness DELETE 10K of ~100K rows): SQL 0.82s/12K -> 0.24s/41K ops/s, Direct 0.63s/16K -> 0.17s/58K ops/s; --pk legacy 0.16s/62K, fixed-width 0.13s/78K ops/s. Full suite EXIT=0.
@sonarqubecloud

sonarqubecloud Bot commented Sep 3, 2026

Copy link
Copy Markdown

@MPCoreDeveloper
MPCoreDeveloper changed the base branch from perf/tombstone-delete to master September 3, 2026 19:35
@MPCoreDeveloper
MPCoreDeveloper merged commit 75629c8 into master Sep 3, 2026
2 checks passed
@MPCoreDeveloper
MPCoreDeveloper deleted the perf/commit-time-tombstones branch September 3, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant