%% @Doc Drive a set of lsm BTrees -module(lsm_btree_drv). -behaviour(gen_server). %% API -export([start_link/0]). -export([ delete_exist/2, lookup_exist/2, lookup_fail/2, open/1, close/1, put/3, stop/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -define(SERVER, ?MODULE). -record(state, { btrees = dict:new() % Map from a name to its tree }). %%%=================================================================== start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). call(X) -> gen_server:call(?SERVER, X, infinity). lookup_exist(N, K) -> call({lookup, N, K}). lookup_fail(N, K) -> call({lookup, N, K}). delete_exist(N, K) -> call({delete_exist, N, K}). open(N) -> call({open, N}). close(N) -> call({close, N}). put(N, K, V) -> call({put, N, K, V}). stop() -> call(stop). %%%=================================================================== init([]) -> {ok, #state{}}. handle_call({open, N}, _, #state { btrees = D} = State) -> case lsm_btree:open(N) of {ok, Tree} -> {reply, ok, State#state { btrees = dict:store(N, Tree, D)}}; Otherwise -> {reply, {error, Otherwise}, State} end; handle_call({close, N}, _, #state { btrees = D} = State) -> Tree = dict:fetch(N, D), case lsm_btree:close(Tree) of ok -> {reply, ok, State#state { btrees = dict:erase(N, D)}}; Otherwise -> {reply, {error, Otherwise}, State} end; handle_call({put, N, K, V}, _, #state { btrees = D} = State) -> Tree = dict:fetch(N, D), case lsm_btree:put(Tree, K, V) of ok -> {reply, ok, State}; Other -> {reply, {error, Other}, State} end; handle_call({delete_exist, N, K}, _, #state { btrees = D} = State) -> Tree = dict:fetch(N, D), Reply = lsm_btree:delete(Tree, K), {reply, Reply, State}; handle_call({lookup, N, K}, _, #state { btrees = D} = State) -> Tree = dict:fetch(N, D), Reply = lsm_btree:lookup(Tree, K), {reply, Reply, State}; handle_call(stop, _, #state{ btrees = D } = State ) -> [ lsm_btree:close(Tree) || {_,Tree} <- dict:to_list(D) ], cleanup_trees(State), {stop, normal, ok, State}; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%=================================================================== %% @todo directory cleanup cleanup_trees(#state { btrees = BTs }) -> dict:fold(fun(_Name, Tree, ok) -> lsm_btree:close(Tree) end, ok, BTs).