Skip to content

perf: single-pass contiguous UPDATE for plaintext fixed-width tables - #360

Merged
MPCoreDeveloper merged 1 commit into
masterfrom
perf/bulk-contiguous-update
Sep 3, 2026
Merged

perf: single-pass contiguous UPDATE for plaintext fixed-width tables#360
MPCoreDeveloper merged 1 commit into
masterfrom
perf/bulk-contiguous-update

Conversation

@MPCoreDeveloper

Copy link
Copy Markdown
Owner

Summary

B8: single-pass contiguous UPDATE fast path. When a batch UPDATE (via ExecuteBatchSQLTable.UpdateMultiple) hits a plaintext fixed-width columnar table with strictly ascending pk = <literal> matches whose records are physically adjacent in the data file (fixed-width ⇒ constant stride [4-byte length][FixedSize payload]), the target records are read as one contiguous byte range through the storage layer's cached file handle and patched in memory — no per-row pread.

Measured (AppendOnly --pk, default = fixed-width)

before after
UPDATE ~45K ops/s ~84K ops/s (+86%)
UPDATE gap vs SQLite 5.1× 3.2×

Correctness & scope

  • Strictly gated; any deviation falls back to the generic per-row loop before any record is touched:
    • fixed-width + Columnar + explicit PK; plaintext only (NoEncryptMode) so a raw range equals the logical records;
    • no buffered overwrites for the file (new IStorage.HasBufferedOverwrite) so the range read can never see stale disk bytes;
    • keys strictly increasing, every position verified adjacent (B-tree), every 4-byte length prefix verified;
    • no PK writes, no CHECK constraints; fixed-size hash-indexed SET columns are re-pointed in-batch (old value decoded from the raw slot); variable-length (TEXT/BLOB) indexed columns and encrypted DBs fall back.
  • New IStorage.ReadBytesRange (default null; Storage implements it over the cached read handle — ReadBytesAt's fresh per-call handle conflicted with the transaction's open handles).
  • New Table.BulkContiguousUpdateBatches diagnostics counter; the tests prove the path engages.

Tests

Full suite 1650/1650 (+5 new FixedWidthBulkUpdateTests): engage + durability across reopen, re-engage on a second committed batch (fresh bytes), fallback for gapped keys, fallback for hash-indexed/variable columns with index re-point correctness, fallback for non-plaintext config.

Note: a pre-existing quirk surfaced while writing these tests — a large descending-order ExecuteBatchSQL UPDATE batch silently applies nothing in the generic loop (legacy and fixed-width). Out of scope here; the fallback test uses a gapped-ascending shape instead.

B8: Table.TryBulkUpdateContiguousFixedWidth turns a batch of strictly ascending pk=literal updates on a plaintext fixed-width columnar table into one contiguous range read + in-memory field patches + buffered same-length overwrites (no per-row pread). AppendOnly --pk measured UPDATE ~45K -> ~84K ops/s (+86%); UPDATE gap vs SQLite 5.1x -> 3.2x.

Adds IStorage.HasBufferedOverwrite + IStorage.ReadBytesRange (shared cached handle) so the raw-range read can never observe stale bytes from the transaction write-behind buffer and never opens a conflicting handle inside a transaction. Fixed-size hash-indexed SET columns are re-pointed in-batch from the raw slots; variable-length indexed columns, PK writes, CHECK constraints, encrypted DBs and non-adjacent/descending keys fall back to the generic per-row loop before any write.
@sonarqubecloud

sonarqubecloud Bot commented Sep 3, 2026

Copy link
Copy Markdown

@MPCoreDeveloper
MPCoreDeveloper merged commit a08db3a into master Sep 3, 2026
13 checks passed
@MPCoreDeveloper
MPCoreDeveloper deleted the perf/bulk-contiguous-update branch September 3, 2026 06:42
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