1-module(kv_store).
2-behaviour(gen_server).
3
4-export([start_link/0, get/1, put/2, delete/1,
5 keys/0, size/0]).
6-export([init/1, handle_call/3, handle_cast/2,
7 handle_info/2]).
8
9-record(state, {
10 store = #{} :: map(),
11 hits = 0 :: non_neg_integer(),
12 misses = 0 :: non_neg_integer()
13}).
14
15start_link() ->
16 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
17
18get(Key) ->
19 gen_server:call(?MODULE, {get, Key}).
20
21put(Key, Value) ->
22 gen_server:cast(?MODULE, {put, Key, Value}).
23
24delete(Key) ->
25 gen_server:cast(?MODULE, {delete, Key}).
26
27keys() ->
28 gen_server:call(?MODULE, keys).
29
30size() ->
31 gen_server:call(?MODULE, size).
32
33init([]) ->
34 {ok, #state{}}.
35
36handle_call({get, Key}, _From, State) ->
37 case maps:find(Key, State#state.store) of
38 {ok, Value} ->
39 NewState = State#state{hits = State#state.hits + 1},
40 {reply, {ok, Value}, NewState};
41 error ->
42 NewState = State#state{
43 misses = State#state.misses + 1
44 },
45 {reply, {error, not_found}, NewState}
46 end;
47handle_call(keys, _From, State) ->
48 Keys = maps:keys(State#state.store),
49 {reply, Keys, State};
50handle_call(size, _From, State) ->
51 Size = maps:size(State#state.store),
52 {reply, Size, State}.
53
54handle_cast({put, Key, Value}, State) ->
55 NewStore = maps:put(Key, Value, State#state.store),
56 {noreply, State#state{store = NewStore}};
57handle_cast({delete, Key}, State) ->
58 NewStore = maps:remove(Key, State#state.store),
59 {noreply, State#state{store = NewStore}}.
60
61handle_info(_Info, State) ->
62 {noreply, State}.