basic vnode management stuff

This commit is contained in:
wires 2025-04-03 18:37:32 -04:00
parent d2a77bb174
commit 281938a05d
Signed by: wires
SSH key fingerprint: SHA256:9GtP+M3O2IivPDlw1UY872UPUuJH2gI0yG6ExBxaaiM
5 changed files with 142 additions and 1 deletions

View file

@ -20,7 +20,10 @@ init([]) ->
intensity => 0,
period => 1
},
ChildSpecs = [],
ChildSpecs = [
#{id => vnode_manager, start => {kv_vnode_manager, start_link, []}, type => worker},
#{id => vnode_sup, start => {kv_vnode_sup, start_link, []}, type => supervisor}
],
{ok, {SupFlags, ChildSpecs}}.
%%% internal functions

58
apps/kv/src/kv_vnode.erl Normal file
View file

@ -0,0 +1,58 @@
-module(kv_vnode).
-moduledoc """
Holds data for a single partition in the ring.
""".
-behaviour(gen_server).
-export([
start_link/1,
get/2,
put/3
]).
%%% gen_server callbacks
-export([
init/1,
handle_call/3,
handle_cast/2
]).
-record(kv_vnode, {
index :: non_neg_integer(),
table :: ets:table()
}).
-type state() :: #kv_vnode{}.
%%% public api
-spec start_link(Index :: non_neg_integer()) -> gen_server:start_ret().
start_link(Index) ->
gen_server:start_link(?MODULE, [Index], []).
-spec get(VNode :: gen_server:server_ref(), Key :: term()) -> {ok, Value :: term()} | none.
get(VNode, Key) ->
gen_server:call(VNode, {get, Key}).
-spec put(VNode :: gen_server:server_ref(), Key :: term(), Value :: term()) -> ok.
put(VNode, Key, Value) ->
gen_server:cast(VNode, {put, Key, Value}).
%%% gen_server callbacks
-spec init([Index :: non_neg_integer()]) -> {ok, state()}.
init([Index]) ->
{ok, #kv_vnode{index = Index, table = ets:new(?MODULE, [set, private])}}.
handle_call({get, Key}, _From, #kv_vnode{table = Table} = State) ->
Reply =
case ets:lookup(Table, Key) of
[{_, Value}] -> {ok, Value};
[] -> none
end,
{reply, Reply, State}.
handle_cast({put, Key, Value}, #kv_vnode{table = Table} = State) ->
ets:insert(Table, {Key, Value}),
{noreply, State}.

View file

@ -0,0 +1,44 @@
-module(kv_vnode_manager).
-behaviour(gen_server).
-export([
start_link/0,
get_vnode/1
]).
%%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2]).
-record(kv_vnode_manager, {table :: ets:table()}).
-type state() :: #kv_vnode_manager{}.
%%% public api
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
get_vnode(Index) ->
gen_server:call(?MODULE, {get_vnode, Index}).
%%% gen_server callbacks
-spec init([]) -> {ok, state()}.
init([]) ->
{ok, #kv_vnode_manager{table = ets:new(?MODULE, [set])}}.
handle_call({get_vnode, Index}, _From, State) ->
Table = State#kv_vnode_manager.table,
Reply =
case ets:lookup(Table, Index) of
[{_, Pid}] ->
{ok, Pid};
[] ->
{ok, Pid} = kv_vnode_sup:start_vnode(Index),
ets:insert(Table, {Index, Pid}),
{ok, Pid}
end,
{reply, Reply, State}.
handle_cast(_, _) -> error(not_implemented).

View file

@ -0,0 +1,35 @@
-module(kv_vnode_sup).
-behaviour(supervisor).
-export([start_link/0, start_vnode/1]).
%%% supervisor callbacks
-export([init/1]).
%%% public api
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-spec start_vnode(Index :: non_neg_integer()) -> supervisor:startchild_ret().
start_vnode(Index) ->
supervisor:start_child(?MODULE, [Index]).
%%% supervisor callbacks
init([]) ->
SupFlags = #{
strategy => simple_one_for_one,
intensity => 0,
period => 1
},
ChildSpec = #{
id => undefined,
start => {kv_vnode, start_link, []},
restart => temporary,
type => worker
},
{ok, {SupFlags, [ChildSpec]}}.
%%% internal functions

1
rebar.lock Normal file
View file

@ -0,0 +1 @@
[].