src/marina_cache.erl

-module(marina_cache).
-include("marina_internal.hrl").

-export([
    erase/2,
    erase_pool/1,
    erase_server/1,
    get/2,
    init/0,
    put/3
]).

%% public
-spec erase(atom(), binary()) -> ok | {error, not_found}.

erase(Pool, Key) ->
    try
        ets:delete(?ETS_TABLE_CACHE, {Pool, Key}),
        ok
    catch
        error:badarg ->
            {error, not_found}
    end.

-spec erase_pool(atom()) -> non_neg_integer().

erase_pool(Pool) ->
    ets:select_delete(?ETS_TABLE_CACHE,
        [{{{'$1', '$2'}, '_'}, [{'==', '$1', Pool}], [true]}]).

%% Evict every cached prepared statement for the shackle pool that a
%% given request_id belongs to. Intended for the server-side
%% `Unprepared` (9472) error path from async_reusable_query — once the
%% server has forgotten the statement id, the client's next execute
%% will fail until the cache entry is gone so the statement gets
%% re-prepared.
-spec erase_server(shackle:request_id()) -> ok.

erase_server({ServerName, _}) ->
    _ = erase_pool(marina_utils:server_to_pool(ServerName)),
    ok.

-spec get(atom(), binary()) -> {ok, term()} | {error, not_found}.

get(Pool, Key) ->
    try
        Term = ets:lookup_element(?ETS_TABLE_CACHE, {Pool, Key}, 2),
        {ok, Term}
    catch
        error:badarg ->
            {error, not_found}
    end.

-spec init() -> ?ETS_TABLE_CACHE.

init() ->
    ets:new(?ETS_TABLE_CACHE, [
        named_table,
        public,
        {read_concurrency, true}
    ]).

-spec put(atom(), binary(), term()) -> ok.

put(Pool, Key, Value) ->
    ets:insert(?ETS_TABLE_CACHE, {{Pool, Key}, Value}),
    ok.