0.16.0-rc1 → 0.16.0 GA

What changed between the first release candidate and the shipped release. RC1 was a per-fix probe round + 3.5h soak (2026-07-21); GA was a targeted perf + fix re-verification (2026-07-23). Same test bed: 3× i4i.xlarge db (RF=3, 13 read-replica token ranges) + m5.xlarge app, Cassandra 5.0.8.

Read the methods before the numbers. The two rounds were not run identically. RC1's split-pruning probe measured do_get counter deltas + EXPLAIN split counts (not per-query latency); GA measured 60-sample server-side elapsedTimeMillis. RC1's throughput came from a 3.5h soak; GA's from a 180s loadtest. Where a row isn't apples-to-apples it says so.

The three fixes that moved

Fix0.16.0-rc10.16.0 GAChange
#2806 / #2679 split pruningREGRESSED / inertFIXED13 splits (on==off) → 1 split; the connector now reads the bound key from the pushed-down filterJson on the table handle instead of the empty constraint.getSummary()
#2807 UDT keyspace-qual parseBLOCKED (parse crash)FIXEDrc1 code: Char crash at frozen<ks.udt> → all UDT tables now parse & are queryable
#2349 scalar frozen<udt>unreachable (behind #2807)VERIFIEDdecodes to {street: 2 Oak, zip: 10001}, matches sstabledump
#2815 list<frozen<udt>>column silently dropped (rc2)symptom fixedcolumn now present in schema + SELECT *; elements are raw serialized UDT bytes (correct data, not yet structured — 0.17 candidate)

Split pruning — from inert to a real win

The headline of the whole 0.16 cycle. In RC1 the optimization existed but never fired for the exact query class it targets:

WHERE key = ?0.16.0-rc10.16.0 GA
splits, pruning ON13 (inert)1
splits, pruning OFF1313
ON vs OFF differentialnone (identical)13 → 1
per-query latency effectnot measurable (no fan-out change)p50 −18% (185 → 152 ms)
coordinator CPU / query−4× (8 → 2 ms)

RC1's verdict was regressed → #2806: the pruning logic was correct in isolation but read the wrong source, so keyed reads always fanned out to all 13 read-replica ranges. GA reads the bound key where applyFilter actually put it, and the point read collapses to the single owning split.

Throughput / latency, round over round

RoundThreadsqpsp50p99errorsNotes
soak-0.1532~39798 ms1366 ms090-min steady block
0.16.0-rc132~32990 ms1255 ms03.5h main soak (flat, 0 err)
0.16.0 GA32~33967 ms1195 ms0180s loadtest, pruning ON

Throughput and latency are statistically unchanged rc1 → GA (~32 → ~33 qps, p99 ~1255 → ~1195 ms). The ~32–39 qps ceiling persists across both because it is owned by the fan-out skew (#2680) and snapshot-resolve floor, not by split pruning. What pruning does change under load is the cold ramp and tail: GA pruning-ON reaches steady state faster (15.7 vs 9.9 qps at 30 s with pruning off) and holds a tighter p99.

What GA did not re-measure

GA was a targeted perf + fix re-verify, so a few dimensions RC1 covered were not repeated. These are gaps in the comparison, not regressions:

Dimension0.16.0-rc10.16.0 GA
Multi-hour drift soak3.5h, flat, 0 errnot re-run (180s loadtest only)
Integrity (start == end)1,703,038 == 1,703,038not re-run
Memory / fd / thread stabilityRSS flat, 0 OOM/restartnot captured (no Grafana)
#2681 abort taxonomy0.026% genuine-error SLInot re-measured
Snapshot grace-sweepbackground 312→172, no querynot re-run

The read-path stability characteristics were established sound in RC1's soak and there is no code path in the GA delta expected to change them; a full milestone soak on GA would confirm that if desired.