feat: add database workers

This commit is contained in:
Moritz Böhme 2024-08-07 00:48:49 +02:00
parent a408a38ffb
commit 1550e896a0
Signed by: moritz
GPG key ID: 970C6E89EB0547A9
3 changed files with 81 additions and 17 deletions

View file

@ -1,7 +1,9 @@
defmodule Todo.Database do
alias Todo.DatabaseWorker
use GenServer
@db_folder "./persist"
@num_of_workers 3
def start do
GenServer.start(__MODULE__, nil, name: __MODULE__)
@ -19,33 +21,47 @@ defmodule Todo.Database do
def init(_) do
File.mkdir_p!(@db_folder)
{:ok, nil}
{:ok, nil, {:continue, :init}}
end
@impl GenServer
def handle_cast({:store, key, data}, state) do
key
|> file_name()
|> File.write!(:erlang.term_to_binary(data))
def handle_continue(:init, nil) do
File.mkdir_p!(@db_folder)
{:noreply, state}
workers =
0..(@num_of_workers - 1)
|> Enum.map(fn i ->
{:ok, pid} = Todo.DatabaseWorker.start(@db_folder)
{i, pid}
end)
|> Map.new()
IO.inspect(workers)
{:noreply, workers}
end
@impl GenServer
def handle_call({:get, key}, _, state) do
def handle_cast({:store, key, data}, workers) do
workers
|> get_worker(key)
|> DatabaseWorker.store(key, data)
{:noreply, workers}
end
@impl GenServer
def handle_call({:get, key}, _, workers) do
data =
case File.read(file_name(key)) do
{:ok, contents} ->
:erlang.binary_to_term(contents)
workers
|> get_worker(key)
|> DatabaseWorker.get(key)
_ ->
nil
end
{:reply, data, state}
{:reply, data, workers}
end
def file_name(key) do
Path.join(@db_folder, to_string(key))
defp choose_worker(workers, key) do
id = :erlang.phash2(key, @num_of_workers)
Map.fetch!(workers, id)
end
end

View file

@ -0,0 +1,48 @@
defmodule Todo.DatabaseWorker do
use GenServer
def start(db_folder) do
GenServer.start(__MODULE__, db_folder)
end
def store(pid, key, data) do
GenServer.cast(pid, {:store, key, data})
end
def get(pid, key) do
GenServer.call(pid, {:get, key})
end
@impl GenServer
def init(db_folder) do
{:ok, db_folder}
end
@impl GenServer
def handle_cast({:store, key, data}, db_folder) do
{db_folder, key}
|> file_name()
|> File.write!(:erlang.term_to_binary(data))
{:noreply, db_folder}
end
@impl GenServer
def handle_call({:get, key}, _, db_folder) do
data =
case File.read(file_name({db_folder, key})) do
{:ok, contents} ->
:erlang.binary_to_term(contents)
_ ->
nil
end
{:reply, data, db_folder}
end
def file_name({db_folder, key}) do
Path.join(db_folder, to_string(key))
end
end

BIN
persist/a Normal file

Binary file not shown.