From 75494e6fa3725a1237d423cb3181ceeaf4205bd6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christopher=20Cot=C3=A9?= Date: Tue, 24 Nov 2020 21:32:46 -0600 Subject: [PATCH] adds round-robin update function --- lib/cluster_kv/db.ex | 18 ++++++++++++++++++ lib/cluster_kv/ring.ex | 4 ++-- test/cluster_kv_test.exs | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/cluster_kv/db.ex b/lib/cluster_kv/db.ex index 573aa9d..721414f 100644 --- a/lib/cluster_kv/db.ex +++ b/lib/cluster_kv/db.ex @@ -18,6 +18,7 @@ defmodule ClusterKV.DB do | :last_30 | :unique | :remove + | :round_robin | fun() @type t :: %__MODULE__{ @@ -246,6 +247,7 @@ defmodule ClusterKV.DB do defp get_update_function(:last_30), do: &last_30/2 defp get_update_function(:unique), do: &unique/2 defp get_update_function(:remove), do: &remove/2 + defp get_update_function(:round_robin), do: &round_robin/2 defp get_update_function(fun) when is_function(fun), do: fun defp get_update_function(_), do: fn _, _ -> :noop end @@ -270,6 +272,22 @@ defmodule ClusterKV.DB do defp unique({k, old}, value), do: {k, [value | old] |> Enum.uniq()} defp remove({k, values}, value), do: {k, List.delete(values, value)} + defp round_robin({id, v}, value) do + val = + case v do + [values] -> values + [_ | t] -> Enum.reduce(t, 0, fn a, _acc -> a end) + end + + case val + 1 do + ni when ni < value -> + {id, [ni]} + + _ -> + {id, [0]} + end + end + @spec do_get(db :: module(), key :: String.t()) :: element() | :not_found defp do_get(db, key) do case :ets.lookup(db, key) do diff --git a/lib/cluster_kv/ring.ex b/lib/cluster_kv/ring.ex index 6754c34..52267c1 100644 --- a/lib/cluster_kv/ring.ex +++ b/lib/cluster_kv/ring.ex @@ -50,7 +50,7 @@ defmodule ClusterKV.Ring do keyspace :: String.t(), key :: String.t(), value :: any(), - fun :: atom() + fun :: DB.update_function() ) :: :ok def update(name, keyspace, key, value, fun) do :gen_statem.cast(ClusterKV.ring_name(name), {:update, keyspace, key, value, fun}) @@ -61,7 +61,7 @@ defmodule ClusterKV.Ring do keyspace :: String.t(), key :: String.t(), value :: any(), - fun :: atom() + fun :: DB.update_function() ) :: :updated | :noop def update_if(name, keyspace, key, value, fun) do :gen_statem.call(ClusterKV.ring_name(name), {:update_if, keyspace, key, value, fun}) diff --git a/test/cluster_kv_test.exs b/test/cluster_kv_test.exs index e0493e5..05b9e93 100644 --- a/test/cluster_kv_test.exs +++ b/test/cluster_kv_test.exs @@ -68,6 +68,22 @@ defmodule ClusterKVTest do assert {"test1:test", [:beautiful, :hello, :world]} = ClusterKV.get(db, @keyspace, "test1:test") + + ClusterKV.put(db, @keyspace, "test1:round-robin", 0) + + assert {"test1:round-robin", [0]} = ClusterKV.get(db, @keyspace, "test1:round-robin") + + ClusterKV.update(db, @keyspace, "test1:round-robin", 3, :round_robin) + + assert {"test1:round-robin", [1]} = ClusterKV.get(db, @keyspace, "test1:round-robin") + + ClusterKV.update(db, @keyspace, "test1:round-robin", 3, :round_robin) + + assert {"test1:round-robin", [2]} = ClusterKV.get(db, @keyspace, "test1:round-robin") + + ClusterKV.update(db, @keyspace, "test1:round-robin", 3, :round_robin) + + assert {"test1:round-robin", [0]} = ClusterKV.get(db, @keyspace, "test1:round-robin") end test "update_if", %{db: db} do -- 2.45.3