{:module, KV, bytecode, _} =
defmodule KV do
use GenServer
def start(source) do
{:ok, _pid} = GenServer.start(__MODULE__, source, name: __MODULE__)
:ok
end
def put(key, value) do
for replica <- :pg.get_members(:kv_replicas) do
:ok = GenServer.call(replica, {:put, key, value})
end
:ok
end
def get(key), do: GenServer.call(__MODULE__, {:get, key})
@impl true
def init(source) do
:ok = :pg.join(:kv_replicas, self())
{:ok, %{}, {:continue, {:catch_up, source}}}
end
@impl true
def handle_continue({:catch_up, nil}, map), do: {:noreply, map}
def handle_continue({:catch_up, source}, _map) do
{:noreply, GenServer.call({__MODULE__, source}, :snapshot)}
end
@impl true
def handle_call({:put, k, v}, _from, map), do: {:reply, :ok, Map.put(map, k, v)}
def handle_call({:get, k}, _from, map), do: {:reply, Map.get(map, k), map}
def handle_call(:snapshot, _from, map), do: {:reply, map, map}
end
load = fn n ->
{:module, KV} = :erpc.call(n, :code, :load_binary, [KV, ~c"nofile", bytecode])
{:ok, _} = :erpc.call(n, :pg, :start, [:pg])
end
{:ok, _} = :pg.start_link()
for n <- [a, b], do: load.(n)
for n <- founders, do: :ok = :erpc.call(n, KV, :start, [nil])