Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Hardening

- **NoEncryptMode root cause quantified + explained (P3d)** - definitive 3-rep same-window `--pk-ab`
(tuned vs plain, only NoEncryptMode differs): UPDATE 1.62x, DELETE 1.59x, INSERT 1.31x, READ 1.45x
in favour of `NoEncryptMode=true`. Code audit shows two encryption layers in Storage: per-record
at-rest (`EnableAtRestRecordEncryption`, default off) AND file-level wrappers
(`Storage.ReadWrite`/`PageCache`, `effectiveNoEncrypt = noEncrypt || noEncryption`) gated purely
by `NoEncryptMode`. The default therefore pays AES work on resolution/point/page-cache reads even
though the raw contiguous fast paths are plaintext and still engage. Follow-up (measured via
`--pk-ab`): route hot reads through the raw range path or make the wrapper a no-op when
at-rest encryption is off. Documented in `docs/benchmarks/default-config-pk.md`.

- **Same-window interleaved A/B harness (`--pk-ab`) (P3c)** - new harness mode runs two default-
config variants as alternating rep pairs (A1,B1,A2,B2,...) and reports the per-rep paired median
ratio B/A per phase, so machine drift affects both arms of a pair and cancels out. Smoke (1 rep,
Expand Down
38 changes: 38 additions & 0 deletions docs/benchmarks/default-config-pk.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,44 @@ Preliminary smoke result (1 rep, 2026-09-04, default vs `plain`): UPDATE **1.41x
INSERT 1.21x, READ 1.10x — direction consistent with the earlier medians, now measured inside a
single window. Re-run with the default 3 reps before quoting final numbers.

### Definitive paired A/B (3 reps, tuned vs plain — isolates NoEncryptMode)

`--pk-ab` with `SHARPCOREDB_PK_AB_ARM_A=tuned` (full knob set, `NoEncryptMode=false`) vs
`SHARPCOREDB_PK_AB_ARM_B=plain` (same set, `NoEncryptMode=true`). Same-window per-rep paired medians
(2026-09-04):

| phase | A `tuned` ops/s | B `plain` ops/s | median B/A |
|---|---:|---:|---:|
| UPDATE | 100,647 | 163,083 | **1.62x** |
| DELETE | 87,251 | 105,932 | **1.59x** |
| INSERT | 95,958 | 125,400 | **1.31x** |
| READ | 58,742 | 71,768 | **1.45x** |

`NoEncryptMode` alone is worth a uniform ~1.3-1.6x across every phase.

## Root cause (code audit)

`NoEncryptMode` is NOT only the per-record at-rest gate. In `Storage` there are two layers:

1. **Per-record at-rest encryption** — `EnableAtRestRecordEncryption` (default false) gates
`UseRecordEncryption` for record payloads.
2. **File-level encrypt/decrypt wrappers** — `Storage.noEncryption = !config.NoEncryptMode`
(Storage.Core) is used unconditionally by the whole-file/point read paths that run through
`Storage.ReadWrite` (`ReadBytes`/`WriteBytes`, `effectiveNoEncrypt = noEncrypt || noEncryption`)
and by the page-cache loader `Storage.PageCache.LoadPageFromDisk`. With the default
`NoEncryptMode=false`, every such read pays AES-GCM work even though per-record at-rest
encryption is off.

That is why the fixed-width fast paths still "engage" (raw contiguous `ReadBytesRange` reads are
plaintext and the counters fire) yet default-config throughput is ~1.3-1.6x lower on ALL phases:
the DML resolution, point reads and page-cache reads around the fast paths still flow through the
encrypting/decrypting wrappers. The paired A/B isolates exactly this flag.

Follow-up candidates (only after a measured `--pk-ab` confirmation on each): route the hot
resolution/scan reads through the same raw range path that already bypasses the wrappers, or make
the file-level wrapper a no-op for the (default, at-rest-off) case without weakening real
encryption when `EnableAtRestRecordEncryption` is on.

## Honest conclusion

1. The earlier claim that the default `WalDurabilityMode.FullSync` dominates the gap is **wrong**
Expand Down
Loading