Current section

Files

Jump to
honeydew lib honeydew dispatcher lru_node.ex
Raw

lib/honeydew/dispatcher/lru_node.ex

defmodule Honeydew.Dispatcher.LRUNode do
alias Honeydew.Dispatcher.LRU
# TODO: docs
def init do
# {node_queue, workers}
{:ok, {:queue.new, Map.new}}
end
def available?({_node_queue, workers}) do
workers
|> Map.values
|> Enum.any?(&LRU.available?/1)
end
def check_in(worker, {node_queue, workers}) do
node = worker_node(worker)
{node_queue, node_workers} =
workers
|> Map.get(node)
|> case do
nil ->
# this node isn't currently known
{:ok, node_workers} = LRU.init
{:queue.in(node, node_queue), node_workers}
node_workers ->
# there's already at least one worker from this node present
{node_queue, node_workers}
end
{node_queue, Map.put(workers, node, LRU.check_in(worker, node_workers))}
end
def check_out(job, {node_queue, workers} = state) do
with {{:value, node}, node_queue} <- :queue.out(node_queue),
%{^node => node_workers} <- workers,
{worker, node_workers} when not is_nil(worker) <- LRU.check_out(job, node_workers) do
if :queue.is_empty(node_workers) do
{worker, {node_queue, Map.delete(workers, node)}}
else
{worker, {:queue.in(node, node_queue), Map.put(workers, node, node_workers)}}
end
else _ ->
{nil, state}
end
end
def remove(worker, {node_queue, workers}) do
node = worker_node(worker)
with %{^node => node_workers} <- workers,
node_workers <- LRU.remove(worker, node_workers) do
if LRU.available?(node_workers) do
{node_queue, Map.put(workers, node, node_workers)}
else
{:queue.filter(&(&1 != node), node_queue), Map.delete(workers, node)}
end
else _ ->
# this means that we've been asked to remove a worker we don't know about
# this should never happen :o
{node_queue, workers}
end
end
# for testing
defp worker_node({_worker, node}), do: node
defp worker_node(worker) do
:erlang.node(worker)
end
end