%%%------------------------------------------------------------------- %%% @private %%% @doc %%% Prefix tree server - This server provides a shared subject tree %%% between members of the same ranch socket listener pool. %%% @end %%%------------------------------------------------------------------- -module(denrei_tree_server). -behaviour(gen_server). %% API -export([start/0, start_link/0, stop/1]). -export([insert/3, delete/3, match/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -define(SERVER, ?MODULE). %%%=================================================================== %%% API %%%=================================================================== -spec insert(pid(), any(), denrei_tree:keys()) -> ok. insert(Pid, Value, Keys) -> gen_server:call(Pid, {insert, Value, Keys}). -spec delete(pid(), any(), denrei_tree:keys() | all) -> ok. delete(Pid, Value, Keys) -> gen_server:call(Pid, {delete, Value, Keys}). -spec match(pid(), denrei_tree:keys()) -> {ok, denrei_tree:values()}. match(Pid, Keys) -> gen_server:call(Pid, {match, Keys}). %%-------------------------------------------------------------------- %% @doc %% Starts the server %% %% @end %%-------------------------------------------------------------------- -spec(start() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). start() -> gen_server:start(?MODULE, [], []). -spec(start_link() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). start_link() -> gen_server:start_link(?MODULE, [], []). -spec(stop(Pid :: pid()) -> ok). stop(Pid) -> gen_server:cast(Pid, stop). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== %%-------------------------------------------------------------------- %% @private %% @doc %% Initializes the server %% %% @spec init(Args) -> {ok, Tree} | %% {ok, Tree, Timeout} | %% ignore | %% {stop, Reason} %% @end %%-------------------------------------------------------------------- -spec(init(Args :: term()) -> {ok, Tree :: denrei_tree:tree()} | {ok, Tree :: denrei_tree:tree(), timeout() | hibernate} | {stop, Reason :: term()} | ignore). init([]) -> {ok, denrei_tree:new()}. %%-------------------------------------------------------------------- %% @private %% @doc %% Handling call messages %% %% @end %%-------------------------------------------------------------------- -spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, Tree :: denrei_tree:tree()) -> {reply, Reply :: term(), NewTree :: denrei_tree:tree()} | {reply, Reply :: term(), NewTree :: denrei_tree:tree(), timeout() | hibernate} | {noreply, NewTree :: denrei_tree:tree()} | {noreply, NewTree :: denrei_tree:tree(), timeout() | hibernate} | {stop, Reason :: term(), Reply :: term(), NewTree :: denrei_tree:tree()} | {stop, Reason :: term(), NewTree :: denrei_tree:tree()}). handle_call({insert, Value, Keys}, _From, Tree) -> {reply, ok, denrei_tree:insert(Value, Keys, Tree)}; handle_call({delete, Value, Keys}, _From, Tree) -> {reply, ok, denrei_tree:delete(Value, Keys, Tree)}; handle_call({match, Keys}, _From, Tree) -> {reply, {ok, denrei_tree:match(Keys, Tree)}, Tree}; handle_call(_Request, _From, Tree) -> {reply, ok, Tree}. %%-------------------------------------------------------------------- %% @private %% @doc %% Handling cast messages %% %% @end %%-------------------------------------------------------------------- -spec(handle_cast(Request :: term(), Tree :: denrei_tree:tree()) -> {noreply, NewTree :: denrei_tree:tree()} | {noreply, NewTree :: denrei_tree:tree(), timeout() | hibernate} | {stop, Reason :: term(), NewTree :: denrei_tree:tree()}). handle_cast(_Request, Tree) -> {noreply, Tree}. %%-------------------------------------------------------------------- %% @private %% @doc %% Handling all non call/cast messages %% %% @spec handle_info(Info, Tree) -> {noreply, Tree} | %% {noreply, Tree, Timeout} | %% {stop, Reason, Tree} %% @end %%-------------------------------------------------------------------- -spec(handle_info(Info :: timeout() | term(), Tree :: denrei_tree:tree()) -> {noreply, NewTree :: denrei_tree:tree()} | {noreply, NewTree :: denrei_tree:tree(), timeout() | hibernate} | {stop, Reason :: term(), NewTree :: denrei_tree:tree()}). handle_info(_Info, Tree) -> {noreply, Tree}. %%-------------------------------------------------------------------- %% @private %% @doc %% This function is called by a gen_server when it is about to %% terminate. It should be the opposite of Module:init/1 and do any %% necessary cleaning up. When it returns, the gen_server terminates %% with Reason. The return value is ignored. %% %% @spec terminate(Reason, Tree) -> void() %% @end %%-------------------------------------------------------------------- -spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), Tree :: denrei_tree:tree()) -> term()). terminate(_Reason, _Tree) -> ok. %%-------------------------------------------------------------------- %% @private %% @doc %% Convert process state when code is changed %% %% @spec code_change(OldVsn, Tree, Extra) -> {ok, NewTree} %% @end %%-------------------------------------------------------------------- -spec(code_change(OldVsn :: term() | {down, term()}, Tree :: denrei_tree:tree(), Extra :: term()) -> {ok, NewTree :: denrei_tree:tree()} | {error, Reason :: term()}). code_change(_OldVsn, Tree, _Extra) -> {ok, Tree}. %%%=================================================================== %%% Internal functions %%%===================================================================