diff --git a/lib/todo/database.ex b/lib/todo/database.ex index 07862fd..b67dfb8 100644 --- a/lib/todo/database.ex +++ b/lib/todo/database.ex @@ -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 diff --git a/lib/todo/database_worker.ex b/lib/todo/database_worker.ex new file mode 100644 index 0000000..8a2e265 --- /dev/null +++ b/lib/todo/database_worker.ex @@ -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 diff --git a/persist/a b/persist/a new file mode 100644 index 0000000..dca63f3 Binary files /dev/null and b/persist/a differ