# v0.52.0 — DVM Hot-Path Performance

> **Full details:** [v0.52.0.md-full.md](v0.52.0.md-full.md)

## What's New

v0.52.0 focuses entirely on eliminating four measurable hot-path costs in
the DVM differential refresh pipeline, all identified in the v0.51.0 overall
assessment (Report 11).

### O(1) Placeholder Resolution (P-1)

The `resolve_delta_template()` function previously called `.replace()` twice
per source table OID — a full string scan for every placeholder. For a
10-table join query (~50KB SQL), this meant 20 full-string scans per refresh
cycle. v0.52.0 replaces this with a single-pass [Aho-Corasick](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm)
search that resolves **all** `__PGS_PREV_LSN_{oid}__` / `__PGS_NEW_LSN_{oid}__`
tokens in one traversal — O(template_length) instead of O(k × template_length).

### Thread-Local Volatility Cache (P-2)

`lookup_function_volatility()` previously issued an SPI round-trip to
`pg_proc` for every function name encountered during DVM parsing. A query
with 50 function calls triggered 50 round-trips (~50ms overhead). v0.52.0
adds a thread-local `HashMap<String, char>` cache so each function name is
looked up at most once per backend session.

### Lazy DiffContext Allocations (P-3)

`DiffContext::new()` unconditionally initialized 12 `HashMap`s, including
several that are only ever populated for special query patterns
(ST-to-ST dependencies, fused-chain execution, COALESCE-wrapped aggregates).
v0.52.0 wraps the most commonly empty maps in `Option<HashMap>` so they are
only allocated on first use.

### O(1) LRU Template Cache Eviction (P-8)

The MERGE template cache previously found the least-recently-used entry by
scanning all entries for the minimum `last_used` counter — O(N) per eviction.
v0.52.0 replaces the manual `HashMap` + counter with the `lru` crate's
`LruCache`, which provides O(1) put/get/eviction.

### Fix filter.rs expect() (C-1)

Replaced a bare `.expect("BUG: …")` in the HAVING-filter delta path with a
proper `PgTrickleError::InternalError` return so an invariant violation is
reported as a clean error rather than a backend crash.
