diff --git a/lib/archethic_cache/lru.ex b/lib/archethic_cache/lru.ex index bb54cf4ea..f7a937e14 100644 --- a/lib/archethic_cache/lru.ex +++ b/lib/archethic_cache/lru.ex @@ -128,13 +128,28 @@ defmodule ArchethicCache.LRU do end defp evict_until( - state = %{table: table, keys: keys, evict_fn: evict_fn, bytes_used: bytes_used}, + state = %{keys: keys}, + predicate + ) do + # we reverse the keys here so we don't need to reverse them in a loop + state = %{state | keys: Enum.reverse(keys)} + new_state = do_evict_until(state, predicate) + %{new_state | keys: Enum.reverse(new_state.keys)} + end + + defp do_evict_until( + state = %{ + table: table, + keys: reversed_keys, + evict_fn: evict_fn, + bytes_used: bytes_used + }, predicate ) do if predicate.(state) do state else - case Enum.reverse(keys) do + case reversed_keys do [] -> state @@ -142,7 +157,7 @@ defmodule ArchethicCache.LRU do [{_, {size, oldest_value}}] = :ets.take(table, oldest_key) evict_fn.(oldest_key, oldest_value) - evict_until( + do_evict_until( %{ state | bytes_used: bytes_used - size, diff --git a/test/archethic_cache/lru_test.exs b/test/archethic_cache/lru_test.exs index f96f8ab03..7d0b0fba5 100644 --- a/test/archethic_cache/lru_test.exs +++ b/test/archethic_cache/lru_test.exs @@ -43,13 +43,13 @@ defmodule ArchethicCache.LRUTest do end test "should evict some cached values when there is not enough space available" do - binary = get_a_binary_of_bytes(200) + binary = :crypto.strong_rand_bytes(200) {:ok, pid} = LRU.start_link(:my_cache, 500) LRU.put(:my_cache, :key1, binary) LRU.put(:my_cache, :key2, binary) - LRU.put(:my_cache, :key3, get_a_binary_of_bytes(400)) + LRU.put(:my_cache, :key3, :crypto.strong_rand_bytes(400)) :sys.get_state(pid) @@ -58,7 +58,7 @@ defmodule ArchethicCache.LRUTest do end test "should evict the LRU" do - binary = get_a_binary_of_bytes(200) + binary = :crypto.strong_rand_bytes(200) {:ok, pid} = LRU.start_link(:my_cache, 500) @@ -76,8 +76,29 @@ defmodule ArchethicCache.LRUTest do assert nil == LRU.get(:my_cache, :key2) end + test "should evict the LRU in order" do + binary = :crypto.strong_rand_bytes(200) + + {:ok, pid} = LRU.start_link(:my_cache, 1000) + + LRU.put(:my_cache, :key1, binary) + LRU.put(:my_cache, :key2, binary) + LRU.put(:my_cache, :key3, binary) + LRU.put(:my_cache, :key4, binary) + LRU.put(:my_cache, :key5, binary) + + :sys.get_state(pid) + + LRU.put(:my_cache, :key6, :crypto.strong_rand_bytes(400)) + + :sys.get_state(pid) + + assert nil == LRU.get(:my_cache, :key1) + assert nil == LRU.get(:my_cache, :key2) + end + test "should not cache a binary bigger than cache size" do - binary = get_a_binary_of_bytes(500) + binary = :crypto.strong_rand_bytes(500) {:ok, pid} = LRU.start_link(:my_cache, 200) @@ -89,7 +110,7 @@ defmodule ArchethicCache.LRUTest do end test "should remove all when purged" do - binary = get_a_binary_of_bytes(100) + binary = :crypto.strong_rand_bytes(100) {:ok, _pid} = LRU.start_link(:my_cache, 500) @@ -117,14 +138,4 @@ defmodule ArchethicCache.LRUTest do assert "value1b" == LRU.get(:my_cache2, :key1) end end - - defp get_a_binary_of_bytes(bytes) do - get_a_binary_of_bytes(bytes, <<>>) - end - - defp get_a_binary_of_bytes(0, acc), do: acc - - defp get_a_binary_of_bytes(bytes, acc) do - get_a_binary_of_bytes(bytes - 1, <<0::8, acc::binary>>) - end end