kura_query_cache (kura v2.20.7)
View SourceETS-based cache for compiled query results.
Caches {SQL, Params} tuples keyed by {RepoMod, Query} so two repos
with different dialects don't share entries. Identical queries through
the same repo skip recompilation.
The key carries the whole query term rather than a hash of it: an entry holds bound parameters as well as SQL, so serving the wrong entry would hand a caller another query's rows rather than merely a slower path. ETS hashes the term itself, so hashing the key by hand only reintroduces a collision class the table had already eliminated.
Bound parameters are part of both key and value, so a parameterised query interns a fresh entry per distinct value set and the table only ever grows. Two limits bound it, both counted in words and both configurable:
query_cache_max_memory(default 8000000 words, ~64 MB on 64-bit) - once the table exceeds it the whole cache is dropped and refills.query_cache_max_entry_size(default 4096 words) - a single result bigger than this is never interned.
The per-entry ceiling is the load-bearing one. A where {id, in, List}
built from a caller-supplied array stores that list in both key and
value, so capping entry count alone would still let a few thousand
oversized entries exhaust the node.
See kura#163 for the shape-only cache that removes the need for either.
The ETS table is owned by kura_query_cache_owner (a gen_server under
kura_sup), so the table survives any caller exiting.
Summary
Functions
Drop every cached entry. Required after swapping a repo's dialect at runtime, since the dialect is not part of the cache key. Also used by tests.
Look up a cached compiled query by key.
Initialize the query cache ETS table. No-op when the cache owner is already running (the normal app-startup path). Used by tests that exercise the cache without starting the kura app.
Store a compiled query result for a key. Skips entries larger than
query_cache_max_entry_size, and drops the whole cache first when it has
grown past query_cache_max_memory, so a workload of parameterised
queries cannot grow the table without bound.
Functions
-spec flush() -> ok.
Drop every cached entry. Required after swapping a repo's dialect at runtime, since the dialect is not part of the cache key. Also used by tests.
Look up a cached compiled query by key.
-spec init() -> ok.
Initialize the query cache ETS table. No-op when the cache owner is already running (the normal app-startup path). Used by tests that exercise the cache without starting the kura app.
-spec init([]) -> {ok, []}.
Store a compiled query result for a key. Skips entries larger than
query_cache_max_entry_size, and drops the whole cache first when it has
grown past query_cache_max_memory, so a workload of parameterised
queries cannot grow the table without bound.
Dropping is not atomic with the insert, so concurrent putters can transiently overshoot the limit or wipe each other's entry. Both cost a recompile on the next lookup; neither can serve a wrong entry.
-spec start_link() -> gen_server:start_ret().