Skip to content

perf(core): cut per-row overhead on the result-mapping hot path#277

Merged
zantvoort merged 1 commit into
mainfrom
perf/result-mapping-hot-path
Jul 16, 2026
Merged

perf(core): cut per-row overhead on the result-mapping hot path#277
zantvoort merged 1 commit into
mainfrom
perf/result-mapping-hot-path

Conversation

@zantvoort

Copy link
Copy Markdown
Collaborator

Reduces work done while materializing result sets, on the paths that run for every row of every query. Behavior is unchanged; the full storm-core suite (2305 tests) passes.

Changes

QueryImpl — resolve the column reader once per column, not per cell.
The per-column target-type dispatch (a large switch over the target Class) previously ran for every column of every row. It now resolves a ColumnReader once per column per query, cached per target type via a ClassValue, and reuses it for every row. Reference-returning JDBC getters (String, BigDecimal, temporal types, …) drop the redundant wasNull() probe since they already yield null for SQL NULL; primitive getters keep it.

WeakInterner — key entities by type + primary key, no Ref allocation.
Entity interning previously built a Ref per lookup and store. It now uses a two-level Class → (pk → weak ref) map keyed by the primary key value already in hand, avoiding the per-entity Ref allocation while preserving identity semantics (same type + pk = same canonical instance). ReferenceQueue cleanup is retained via a two-argument remove.

RecordMapper — reuse cached plan metadata, short-circuit the cache lookup.
The parameter-count check reuses the compiled plan's cached parameterTypes().length instead of re-walking the record structure on every query. The entity-cache resolution short-circuits the dirty-tracking mode lookup for non-transactional / non-entity reads, so it is never computed when it cannot apply.

Verification

  • mvn -pl storm-core test — 2305 tests, 0 failures/errors (JDK 21). Directly-affected suites (WeakInternerTest, QueryImplTypeMappingIntegrationTest, EntityCacheImplTest) all green.

Reduce work done while materializing result sets:

- QueryImpl: resolve the JDBC column reader once per column per query
  (cached per target type via ClassValue) instead of re-running the
  target-type switch for every column of every row. Reference-returning
  getters skip the now-redundant wasNull() probe.
- WeakInterner: key entities by concrete type then primary key in a
  two-level map, avoiding a Ref allocation per interned entity while
  keeping the same identity semantics.
- RecordMapper: reuse the compiled plan's cached parameterTypes length
  instead of re-walking the record structure on every query, and
  short-circuit the dirty-tracking lookup for non-transactional reads.
@zantvoort
zantvoort merged commit 4bd541e into main Jul 16, 2026
7 checks passed
@zantvoort
zantvoort deleted the perf/result-mapping-hot-path branch July 16, 2026 15:23
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