+1
-1
.formatter.exs
+1
-1
.formatter.exs
+52
lib/esl_hn/cache.ex
+52
lib/esl_hn/cache.ex
···
1
+
defmodule EslHn.Cache do
2
+
use GenServer
3
+
4
+
def start_link(opts) do
5
+
with {:ok, pid} <- GenServer.start_link(__MODULE__, opts) do
6
+
tid = GenServer.call(pid, :get_tid)
7
+
8
+
{:ok, pid, tid}
9
+
end
10
+
end
11
+
12
+
def read(tid, key) do
13
+
case :ets.lookup(tid, key) do
14
+
[{^key, data}] -> {:ok, data}
15
+
_ -> :error
16
+
end
17
+
end
18
+
19
+
def write(tid, key, data) do
20
+
true = :ets.insert(tid, {key, data})
21
+
22
+
:ok
23
+
end
24
+
25
+
@impl true
26
+
def init(opts) do
27
+
{name, opts} =
28
+
case Access.fetch(opts, :name) do
29
+
{:ok, name} -> {name, [:named_table]}
30
+
:error -> {nil, []}
31
+
end
32
+
33
+
tid =
34
+
:ets.new(
35
+
name,
36
+
opts ++
37
+
[
38
+
:set,
39
+
:public,
40
+
write_concurrency: :auto,
41
+
read_concurrency: true
42
+
]
43
+
)
44
+
45
+
{:ok, %{tid: tid}}
46
+
end
47
+
48
+
@impl true
49
+
def handle_call(:get_tid, _ref, state) do
50
+
{:reply, state.tid, state}
51
+
end
52
+
end
+2
-1
mix.exs
+2
-1
mix.exs
+1
mix.lock
+1
mix.lock
···
22
22
"plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"},
23
23
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
24
24
"req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"},
25
+
"stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"},
25
26
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
26
27
"telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
27
28
"telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"},
+37
test/esl_hn/cache_test.exs
+37
test/esl_hn/cache_test.exs
···
1
+
defmodule EslHn.CacheTest do
2
+
use ExUnit.Case, async: true
3
+
use ExUnitProperties
4
+
5
+
@subject EslHn.Cache
6
+
7
+
doctest @subject
8
+
9
+
describe "unnamed cache" do
10
+
property "we can read written data" do
11
+
assert {:ok, _pid, tid} = start_supervised(@subject)
12
+
13
+
check all(key <- term(), data <- term()) do
14
+
assert :ok == @subject.write(tid, key, data)
15
+
assert {:ok, data} == @subject.read(tid, key)
16
+
end
17
+
end
18
+
19
+
test "fetching non existent key result in error" do
20
+
assert {:ok, _pid, tid} = start_supervised(@subject)
21
+
22
+
assert :error == @subject.read(tid, :non_existent)
23
+
end
24
+
end
25
+
26
+
describe "named cache" do
27
+
property "we can read written data", ctx do
28
+
name = ctx.test
29
+
assert {:ok, _pid, _tid} = start_supervised({@subject, name: name})
30
+
31
+
check all(key <- term(), data <- term()) do
32
+
assert :ok == @subject.write(name, key, data)
33
+
assert {:ok, data} == @subject.read(name, key)
34
+
end
35
+
end
36
+
end
37
+
end