ETS-based prepared statement cache for ScyllaDB/Cassandra queries.
Caches prepared statements keyed by {repo, cql, keyspace, opts} to
eliminate repeated query parsing overhead on ScyllaDB. This is especially
impactful for high-throughput workloads where the same queries are executed
repeatedly.
Cache hits are served directly from ETS by the calling process (lock-free, no GenServer hop); only misses, invalidations, and eviction go through the GenServer so that writes remain serialized and race-free.
Usage
AshScylla.PreparedStatementCache.prepare(repo, "SELECT * FROM users WHERE id = ?")Starting the Cache
Add to your supervision tree:
children = [
AshScylla.PreparedStatementCache,
# ... other children
]Or start manually:
AshScylla.PreparedStatementCache.start_link([])Limits
- Max cache size: 10,000 entries
- Cleanup interval: 5 minutes
- Registered locally as
__MODULE__by default
Summary
Functions
Returns a specification to start this module under a supervisor.
Clears all cached prepared statements.
Evicts the oldest count entries from the cache.
Invalidates a specific cached statement by CQL string.
Returns the configured maximum cache size.
Prepares a CQL statement, using the cache if available.
Returns the number of cached statements.
Starts the prepared statement cache.
Returns the ETS table tid for inspection/testing.
Types
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec clear() :: :ok
Clears all cached prepared statements.
@spec evict_oldest(:ets.tid(), non_neg_integer()) :: :ok
Evicts the oldest count entries from the cache.
Exposed for testing the eviction logic.
@spec invalidate(String.t()) :: :ok
Invalidates a specific cached statement by CQL string.
@spec max_cache_size() :: non_neg_integer()
Returns the configured maximum cache size.
Exposed for testing.
Prepares a CQL statement, using the cache if available.
Cache hits are read straight from ETS by the calling process; misses fall back to the GenServer, which prepares the statement and caches it.
Returns {:ok, stmt} on success or {:error, reason} on failure.
@spec size() :: non_neg_integer()
Returns the number of cached statements.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the prepared statement cache.
When no :name option is given, the GenServer is registered locally
as __MODULE__ so that each node runs its own per-node cache. This is
required in a clustered deployment (libcluster + K8s/gossip), where a
global name would be contested by every node and cause repeated
:reached_max_restart_intensity crashes.
Pass a {:global, name} tuple to register globally, or a custom local
name to register under a different local name.
@spec table() :: :ets.tid() | nil
Returns the ETS table tid for inspection/testing.