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.
All ETS operations are routed through the GenServer to avoid race conditions when multiple processes access the cache concurrently.
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.
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.