Skip to content

feat(tokens): prepare UnspentTokensIteratorBy statements by argument shape#1889

Open
sid200727 wants to merge 1 commit into
LFDT-Panurus:mainfrom
sid200727:feat/prepared-statements-unspent-tokens
Open

feat(tokens): prepare UnspentTokensIteratorBy statements by argument shape#1889
sid200727 wants to merge 1 commit into
LFDT-Panurus:mainfrom
sid200727:feat/prepared-statements-unspent-tokens

Conversation

@sid200727

Copy link
Copy Markdown
Contributor

Summary

Implements prepared statements for UnspentTokensIteratorBy per the design discussed on #1183, following the benchmark work in #1855 that measured the win (+11% throughput, -73% P99 latency, -80% allocs/op).

Changes

-> Added on-demand prepared-statement caching to TokenStore, keyed by argument shape (walletID present/absent, tokenType present/absent)
-> The 3 shapes that occur in current production call sites (documented on #1183) are each prepared once on first use and reused for all subsequent calls of that shape
-> Any call falling outside those 3 shapes (shouldn't happen given today's callers, but handled defensively) falls back to the existing dynamic query-building path, same for any prepare/execute error, so this degrades gracefully rather than failing
-> Close() now closes all cached prepared statements before closing the DB connections

Design notes

  • Statements are prepared lazily (on first use per shape) rather than eagerly at construction, since newTokenStore has no context/error return today and eager preparation would ripple that signature change through every constructor caller. Happy to revisit if eager preparation is preferred.
  • Cache key is a cheap 2-byte shape encoding (walletID present?, tokenType present?), not the argument values themselves, statements are shared across different wallet/type values of the same shape.

Testing

-> New unit test (tokens_prepared_test.go in common) covers the shape-key logic directly
-> New integration test (tokens_prepared_test.go in postgres) verifies statement reuse across repeated/varied calls of the same shape, and distinct caching per shape, against real Postgres
-> Existing TestTokens suite passes unchanged on both sqlite and postgres

Closes #1183

@AkramBitar AkramBitar requested review from AkramBitar and adecaro July 10, 2026 16:59
@AkramBitar AkramBitar added the enhancement New feature or request label Jul 10, 2026
…shape

Introduces on-demand prepared-statement caching for UnspentTokensIteratorBy,
keyed by argument shape (walletID present/absent, tokenType present/absent).
The 3 shapes that occur in production (see call-site analysis on LFDT-Panurus#1183) are
each prepared once and reused; anything outside that set falls back to the
existing dynamic query-building path.

Benchmarked in LFDT-Panurus#1855: +11% throughput, -73% P99 latency, -80% allocs/op
(prepared vs dynamic, median of 3 runs).

Closes LFDT-Panurus#1183

Signed-off-by: Siddhi Khandelwal <siddhi.200727@gmail.com>
@sid200727 sid200727 force-pushed the feat/prepared-statements-unspent-tokens branch from 101a3d7 to 84fd06c Compare July 11, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce SQL Prepared Statements

2 participants