]> Entropealabs - cluster_kv.git/commitdiff
adds round-robin update function local-update
authorChristopher Coté <ccote@cohesionib.com>
Wed, 25 Nov 2020 03:32:46 +0000 (21:32 -0600)
committerChristopher Coté <ccote@cohesionib.com>
Wed, 25 Nov 2020 03:32:46 +0000 (21:32 -0600)
lib/cluster_kv/db.ex
lib/cluster_kv/ring.ex
test/cluster_kv_test.exs

index 573aa9d674539ffc31f502735f1dca7f62b5b05e..721414f2899b8183452c5ffd97f8583b22ca46c1 100644 (file)
@@ -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
index 6754c34959b8b6681b3615dcb6b587169a1cd2f5..52267c13e5dd06fa98bf3d8d0cdf49eed37a69f9 100644 (file)
@@ -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})
index e0493e50e9be73022e5cb6da86b984a20d0d1d77..05b9e937d7854887b3b30fc7a327bbb63cc04ff3 100644 (file)
@@ -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