From 70a5acb01e52ea641f62018d0e3c67ed7f03745d Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Mon, 30 Dec 2024 19:04:23 +0100 Subject: [PATCH 1/2] Feat: implement cache reset function --- CHANGELOG.md | 11 ++++++++++- README.md | 6 +++++- lib/gen_cache.ex | 10 ++++++++++ lib/gen_cache/macro.ex | 1 + lib/gen_cache/macro_test.exs | 13 +++++++++++++ lib/gen_cache_test.exs | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 302fee4..4b4268f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ +## v0.1.2 (2024-12-30) + +### Implements Reset function + +- `GenCache.reset(pid)` +- or macro-based module: `SomeCache.reset()` + + ## v0.1.1 (2024-09-09) + ### Quality of life improvements - allow configuring default ttl when starting the server @@ -11,4 +20,4 @@ ### First release -- already quite usable, there might still be some missing features \ No newline at end of file +- already quite usable, there might still be some missing features diff --git a/README.md b/README.md index bd457a9..747ff87 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ res = MyCache.request({IO, :puts, ["Hello World"]}) # this will not execute the MFA tuple and just return the cached result res = MyCache.request({IO, :puts, ["Hello World"]}) +# remove a single entry from cache +MyCache.remove({IO, :puts, ["Hello World"]}) + +# Reset the complete cache +MyCache.reset() # add custom ttl for the given key res = MyCache.request({IO, :puts, ["Quick one"]}, ttl: :timer.seconds(5)) @@ -59,4 +64,3 @@ end Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) and published on [HexDocs](https://hexdocs.pm). Once published, the docs can be found at . - diff --git a/lib/gen_cache.ex b/lib/gen_cache.ex index 5bb61c8..356a88d 100644 --- a/lib/gen_cache.ex +++ b/lib/gen_cache.ex @@ -67,6 +67,7 @@ defmodule GenCache do def request(pid, request, opts \\ []), do: :gen_statem.call(pid, {:request, request, opts}) def remove(pid, request), do: :gen_statem.call(pid, {:remove, request}) def get_state(pid), do: :gen_statem.call(pid, :get_state) + def reset(pid), do: :gen_statem.call(pid, :reset) ### INTERNAL ### @@ -87,6 +88,11 @@ defmodule GenCache do {:keep_state, data, [{:reply, from, :ok}]} end + def handle_event({:call, from}, :reset, _state, data) do + data = reset_cache(data) + {:keep_state, data, [{:reply, from, :ok}]} + end + # def handle_event({:call, from}, {:request, request, req_opts}, _, data) do ttl = Keyword.get(req_opts, :ttl, @default_ttl) @@ -184,6 +190,10 @@ defmodule GenCache do %Data{data | cache: Map.delete(data.cache, request)} end + def reset_cache(data) do + %Data{data | cache: %{}, valid_until: %{}, ttl: %{}} + end + defp get_from_cache(data, request) do res = Map.get(data.cache, request, nil) diff --git a/lib/gen_cache/macro.ex b/lib/gen_cache/macro.ex index 3f37a1a..04bc417 100644 --- a/lib/gen_cache/macro.ex +++ b/lib/gen_cache/macro.ex @@ -58,6 +58,7 @@ defmodule GenCache.Macro do def remove(request), do: :gen_statem.call(__MODULE__, {:remove, request}) def get_state(), do: :gen_statem.call(__MODULE__, :get_state) + def reset(), do: :gen_statem.call(__MODULE__, :reset) ### INTERNAL ### diff --git a/lib/gen_cache/macro_test.exs b/lib/gen_cache/macro_test.exs index d890676..66fa7b0 100644 --- a/lib/gen_cache/macro_test.exs +++ b/lib/gen_cache/macro_test.exs @@ -20,4 +20,17 @@ defmodule GenCache.MacroTest do {:ok, pid} = TestCache.start_link() assert {:error, {:already_started, pid}} == TestCache.start_link() end + + test "reset works" do + TestCache.start_link() + TestCache.request({Process, :send, [self(), :start, []]}) + TestCache.request({Process, :send, [self(), :start, []]}) + assert_received :start + refute_received :start + + ## RESET clears the cache, so the next request MUST be executed + TestCache.reset() + TestCache.request({Process, :send, [self(), :start, []]}) + assert_received :start + end end diff --git a/lib/gen_cache_test.exs b/lib/gen_cache_test.exs index 244eb81..a5087ae 100644 --- a/lib/gen_cache_test.exs +++ b/lib/gen_cache_test.exs @@ -136,6 +136,42 @@ defmodule GenCacheTest do end end + describe "reset" do + test "resets cache" do + {:ok, pid} = GenCache.start_link([]) + GenCache.request(pid, req_tuple(1)) + GenCache.request(pid, req_tuple(2)) + res = clean_state(pid) + + assert res == %GenCache.Data{ + ttl: %{ + {GenCacheTest.ReqBackend, :fetch, [1]} => 30000, + {GenCacheTest.ReqBackend, :fetch, [2]} => 30000 + }, + busy: %{}, + cache: %{ + {GenCacheTest.ReqBackend, :fetch, [1]} => "RESULT: 1", + {GenCacheTest.ReqBackend, :fetch, [2]} => "RESULT: 2" + }, + valid_until: %{}, + purge_loop: 5000, + default_ttl: 30000 + } + + GenCache.reset(pid) + res = clean_state(pid) + + assert res == %GenCache.Data{ + ttl: %{}, + busy: %{}, + cache: %{}, + valid_until: %{}, + purge_loop: 5000, + default_ttl: 30000 + } + end + end + describe "raising response" do test "is not cached" do defmodule RaisingBackend do From ee369f1a66f24e0c96ce40dd12cd726cd9e79da7 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Mon, 30 Dec 2024 19:04:51 +0100 Subject: [PATCH 2/2] Chore: bump version to 0.1.2 --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index e9ab408..4d5a101 100644 --- a/mix.exs +++ b/mix.exs @@ -2,7 +2,7 @@ defmodule GenCache.MixProject do use Mix.Project @github_url "https://github.com/maxohq/gen_cache" - @version "0.1.1" + @version "0.1.2" @description "gen_statem based generic cache with MFA-based keys" def project do