diff --git a/lib/ring.ex b/lib/ring.ex index 913abe3..1d52622 100644 --- a/lib/ring.ex +++ b/lib/ring.ex @@ -246,7 +246,7 @@ defmodule HashRing do case :gb_trees.iterator_from(hash, r) |> :gb_trees.next() do {_key, node, iter} -> - find_nodes_from_iter(iter, count - 1, [node]) + find_nodes_from_iter(r, iter, count - 1, [node], _restarted? = false) _ -> {_key, node} = :gb_trees.smallest(r) @@ -254,19 +254,24 @@ defmodule HashRing do end end - defp find_nodes_from_iter(_iter, 0, results), do: Enum.reverse(results) + defp find_nodes_from_iter(_ring, _iter, 0, results, _restared?), do: Enum.reverse(results) - defp find_nodes_from_iter(iter, count, results) do + defp find_nodes_from_iter(ring, iter, count, results, restarted?) do case :gb_trees.next(iter) do {_key, node, iter} -> if node in results do - find_nodes_from_iter(iter, count, results) + find_nodes_from_iter(ring, iter, count, results, restarted?) else - find_nodes_from_iter(iter, count - 1, [node | results]) + find_nodes_from_iter(ring, iter, count - 1, [node | results], restarted?) end - _ -> - results + :none -> + if restarted? do + Enum.reverse(results) + else + restart_iter = :gb_trees.iterator(ring) + find_nodes_from_iter(ring, restart_iter, count, results, _restarted? = true) + end end end end diff --git a/test/hashring_test.exs b/test/hashring_test.exs index 962defc..5bb8a9c 100644 --- a/test/hashring_test.exs +++ b/test/hashring_test.exs @@ -19,6 +19,16 @@ defmodule HashRingTest do assert length(nodes) == 2 end + # https://github.com/bitwalker/libring/issues/39 + test "key_to_nodes/3 test 14" do + ring = + HashRing.new() + |> HashRing.add_node(:a@localhost) + |> HashRing.add_node(:b@localhost) + + assert HashRing.key_to_nodes(ring, 14, 2) == [:a@localhost, :b@localhost] + end + property "adding one node leaves us with a tree with one node" do check all(name <- string(:printable, min_length: 1)) do %HashRing{nodes: nodes} = HashRing.new(name)