Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions lib/ring.ex
Original file line number Diff line number Diff line change
Expand Up @@ -246,27 +246,32 @@ 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)
Copy link
Author

@ruslandoga ruslandoga Feb 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if restarted? is needed, but I added it to be safe.


On second though, if we count = min(length(nodes), count) it's not needed.


_ ->
{_key, node} = :gb_trees.smallest(r)
[node]
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)
Copy link
Author

@ruslandoga ruslandoga Feb 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

results were not reversed originally, but I think they need to be since the "happy path" does it (on line 257).

else
restart_iter = :gb_trees.iterator(ring)
find_nodes_from_iter(ring, restart_iter, count, results, _restarted? = true)
end
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions test/hashring_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down