{:module, LeaseStore, bytecode, _} =
defmodule LeaseStore do
use GenServer
def start, do: GenServer.start(__MODULE__, nil, name: __MODULE__)
@impl true
def init(nil) do
{:ok, %{now: 0, holder: nil, token: 0, expires: 0, fence: 0, rows: %{}}}
end
@impl true
def handle_call({:acquire, who, ttl}, _from, s) do
cond do
s.holder == who and s.now < s.expires ->
{:reply, {:ok, s.token}, %{s | expires: s.now + ttl}}
s.holder == nil or s.now >= s.expires ->
token = s.token + 1
{:reply, {:ok, token}, %{s | holder: who, token: token, expires: s.now + ttl}}
true ->
{:reply, {:error, {:held_by, s.holder}}, s}
end
end
def handle_call({:advance, seconds}, _from, s), do: {:reply, :ok, %{s | now: s.now + seconds}}
def handle_call({:put, key, value}, _from, s),
do: {:reply, :ok, %{s | rows: Map.put(s.rows, key, value)}}
def handle_call({:put, key, value, token}, _from, s) when token >= s.fence,
do: {:reply, :ok, %{s | fence: token, rows: Map.put(s.rows, key, value)}}
def handle_call({:put, _key, _value, _token}, _from, s),
do: {:reply, {:error, :stale_token}, s}
def handle_call({:get, key}, _from, s), do: {:reply, Map.get(s.rows, key), s}
end
{:module, LeaseStore} =
:peer.call(peer_db, :code, :load_binary, [LeaseStore, ~c"nofile", bytecode])
{:ok, _} = :peer.call(peer_db, LeaseStore, :start, [])