Skip to content

Commit

Permalink
Merge pull request webmachine#106 from basho/adt-ets-dispatch_list
Browse files Browse the repository at this point in the history
Store the dispatch_list in ETS, not application:set_env
  • Loading branch information
Vagabond committed Jan 21, 2013
2 parents 58f1266 + 154c609 commit 6f59679
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/webmachine_mochiweb.erl
Expand Up @@ -54,7 +54,7 @@ start(Options) ->
{undefined, _} -> {?MODULE, Options5};
{PN, O6} -> {PN, O6}
end,
application_set_unless_env(webmachine, dispatch_list, DispatchList),
webmachine_router:init_routes(DispatchList),
application_set_unless_env(webmachine, error_handler, ErrorHandler),
case RewriteModule of
undefined ->
Expand All @@ -73,7 +73,7 @@ stop() ->

loop(MochiReq) ->
Req = webmachine:new_request(mochiweb, MochiReq),
{ok, DispatchList} = application:get_env(webmachine, dispatch_list),
DispatchList = webmachine_router:get_routes(),
Host = case host_headers(Req) of
[H|_] -> H;
[] -> []
Expand Down
73 changes: 52 additions & 21 deletions src/webmachine_router.erl
Expand Up @@ -26,7 +26,8 @@
add_route/1,
remove_route/1,
remove_resource/1,
get_routes/0]).
get_routes/0,
init_routes/1]).

%% gen_server callbacks
-export([init/1,
Expand Down Expand Up @@ -86,12 +87,31 @@ remove_resource(Resource) when is_atom(Resource) ->
%% @doc Retrieve a list of routes and resources set in webmachine's
%% route table.
get_routes() ->
gen_server:call(?SERVER, get_routes, infinity).
get_dispatch_list().

%% @spec init_routes() -> ok
%% @doc Set the default routes, unless the routing table isn't empty.
init_routes(DefaultRoutes) ->
gen_server:call(?SERVER, {init_routes, DefaultRoutes}, infinity).

%% @spec start_link() -> {ok, pid()} | {error, any()}
%% @doc Starts the webmachine_router gen_server.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%% We expect to only be called from webmachine_sup
%%
%% Set up the ETS configuration table.
try ets:new(?MODULE, [named_table, public, set, {keypos, 1},
{read_concurrency, true}]) of
_Result ->
ok
catch
error:badarg ->
%% The table already exists, which is fine. The webmachine_router
%% probably crashed and this is a restart.
ok
end,

gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%% @private
init([]) ->
Expand All @@ -102,10 +122,6 @@ handle_call({remove_resource, Resource}, _From, State) ->
DL = filter_by_resource(Resource, get_dispatch_list()),
{reply, set_dispatch_list(DL), State};

handle_call(get_routes, _From, State) ->
{reply, get_dispatch_list(), State};


handle_call({remove_route, Route}, _From, State) ->
DL = [D || D <- get_dispatch_list(),
D /= Route],
Expand All @@ -116,6 +132,11 @@ handle_call({add_route, Route}, _From, State) ->
D /= Route]],
{reply, set_dispatch_list(DL), State};

handle_call({init_routes, DefaultRoutes}, _From, State) ->
%% if the table lacks a dispatch_list row, set it
ets:insert_new(?MODULE, {dispatch_list, DefaultRoutes}),
{reply, ok, State};

handle_call(_Request, _From, State) ->
{reply, ignore, State}.

Expand Down Expand Up @@ -153,15 +174,15 @@ filter_by_resource(Resource) ->
end.

get_dispatch_list() ->
case application:get_env(webmachine, dispatch_list) of
{ok, Dispatch} ->
case ets:lookup(?MODULE, dispatch_list) of
[{dispatch_list, Dispatch}] ->
Dispatch;
undefined ->
[] ->
[]
end.

set_dispatch_list(DispatchList) ->
ok = application:set_env(webmachine, dispatch_list, DispatchList),
true = ets:insert(?MODULE, {dispatch_list, DispatchList}),
ok.

%%
Expand All @@ -170,13 +191,9 @@ set_dispatch_list(DispatchList) ->
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").

%% For unit tests only
start() ->
gen_server:start({local, ?SERVER}, ?MODULE, [], []).

add_remove_route_test() ->
application:set_env(webmachine, dispatch_list, []),
{ok, Pid} = start(),
{ok, Pid} = webmachine_sup:start_link(),
unlink(Pid),
PathSpec = {["foo"], foo, []},
webmachine_router:add_route(PathSpec),
[PathSpec] = get_routes(),
Expand All @@ -185,8 +202,8 @@ add_remove_route_test() ->
exit(Pid, kill).

add_remove_resource_test() ->
application:set_env(webmachine, dispatch_list, []),
{ok, Pid} = start(),
{ok, Pid} = webmachine_sup:start_link(),
unlink(Pid),
PathSpec1 = {["foo"], foo, []},
PathSpec2 = {["bar"], foo, []},
PathSpec3 = {["baz"], bar, []},
Expand Down Expand Up @@ -214,12 +231,26 @@ add_remove_resource_test() ->
exit(Pid, kill).

no_dupe_path_test() ->
application:set_env(webmachine, dispatch_list, []),
{ok, Pid} = start(),
{ok, Pid} = webmachine_sup:start_link(),
unlink(Pid),
PathSpec = {["foo"], foo, []},
webmachine_router:add_route(PathSpec),
webmachine_router:add_route(PathSpec),
[PathSpec] = get_routes(),
exit(Pid, kill).

supervisor_restart_keeps_routes_test() ->
{ok, Pid} = webmachine_sup:start_link(),
unlink(Pid),
PathSpec = {["foo"], foo, []},
webmachine_router:add_route(PathSpec),
[PathSpec] = get_routes(),
OldRouter = whereis(webmachine_router),
exit(whereis(webmachine_router), kill),
timer:sleep(100),
NewRouter = whereis(webmachine_router),
?assert(OldRouter /= NewRouter),
[PathSpec] = get_routes(),
exit(Pid, kill).

-endif.

0 comments on commit 6f59679

Please sign in to comment.