Current section

Files

Jump to
super_cache lib storage ets_holder.ex
Raw

lib/storage/ets_holder.ex

defmodule SuperCache.EtsHolder do
@moduledoc false
use GenServer, restart: :permanent
require Logger
alias :ets, as: Ets
alias SuperCache.Config
@spec start_link(any) :: :ignore | {:error, any} | {:ok, pid}
@doc """
Starts the GenServer owner Ets table. The process start then go to hibernate.
"""
def start_link(name) do
GenServer.start_link(__MODULE__, name, name: name)
end
@doc """
Stops GenServer and delete Ets table.
"""
@spec stop(atom | pid | {atom, any} | {:via, atom, any}) :: any
def stop(name) do
GenServer.call(name, :stop)
end
def new_table(name, table_name) do
Logger.debug("new Ets table: #{inspect table_name}")
GenServer.call(name, {:new, table_name})
end
def delete_table(name, table_name) do
Logger.debug("delete Ets table: #{inspect table_name}")
GenServer.call(name, {:delete, table_name})
end
@doc """
Clear all data in Ets table of GenServer.
"""
def clean(name, table_name) do
Logger.debug("clean Ets table: #{inspect table_name}")
GenServer.call(name, {:clean, table_name})
end
def clean_all(name) do
GenServer.call(name, :clean_all)
end
### Callbacks ###
@impl true
def init(name) do
{:ok, %{my_name: name, table_list: []}}
end
@impl true
def handle_call(:stop, _from, state) do
{:stop, :normal, :ok, state}
end
def handle_call({:clean, table_name}, _from, state) do
{:reply, clean_up(table_name), state}
end
def handle_call(:clean_all, _from, state) do
tables = Map.get(state, :table_list)
for table <- tables do
clean_up(table)
end
{:reply, :ok, state}
end
def handle_call({:new, table_name}, _from, state) do
create_table(table_name)
{:reply, :ok, Map.update!(state, :table_list, &([table_name | &1]))}
end
def handle_call({:delete, table_name}, _from, state) do
Ets.delete(table_name)
{:reply, :ok, Map.update!(state, :table_list, &([table_name | &1]))}
end
@impl true
def terminate(reason, %{my_name: name} = state) do
Logger.debug("#{inspect name} shutdown with reason #{inspect reason}")
tables = Map.get(state, :table_list)
for table <- tables do
Ets.delete(table)
end
:stop
end
## Private functions ##
defp clean_up(table_name) do
:ets.delete_all_objects(table_name)
end
defp create_table(table_name) do
Logger.info("create cache table for #{inspect table_name}")
key_pos = Config.get_config(:key_pos) + 1 # key order of ets start from 1
table_type = Config.get_config(:table_type)
^table_name = Ets.new(table_name, [
table_type,
:public,
:named_table,
{:keypos, key_pos},
{:write_concurrency, true},
{:read_concurrency, true},
{:decentralized_counters, true}
])
Logger.info("table #{inspect table_name} is created")
:ok
end
end