From 383181359fcd01df895738e4c0026eb8047147e5 Mon Sep 17 00:00:00 2001 From: benoitc Date: Sun, 8 Jan 2012 19:35:30 +0100 Subject: [PATCH] refactor uuids and change a little the way we start couchbeam. - create couchbeam_uuids module - register couchbeam_sup module - now app are started from the list given in applications key . --- src/couchbeam.app.src | 13 ++-- src/couchbeam.erl | 130 +++------------------------------------- src/couchbeam_app.erl | 8 +-- src/couchbeam_sup.erl | 11 ++-- src/couchbeam_util.erl | 24 ++++++++ src/couchbeam_uuids.erl | 110 ++++++++++++++++++++++++++++++++++ t/002-server.t | 6 +- 7 files changed, 165 insertions(+), 137 deletions(-) create mode 100644 src/couchbeam_uuids.erl diff --git a/src/couchbeam.app.src b/src/couchbeam.app.src index b9f8ee69..bd4b245f 100644 --- a/src/couchbeam.app.src +++ b/src/couchbeam.app.src @@ -1,13 +1,18 @@ %%% -*- erlang -*- %%% -%%% This file is part of couchbeam released under the MIT license. +%%% This file is part of couchbeam released under the MIT license. %%% See the NOTICE for more information. {application, couchbeam, [{description, "Erlang CouchDB kit"}, {vsn, "0.7.3"}, {modules, []}, - {registered, []}, - {applications, [kernel, stdlib, crypto, sasl, ibrowse]}, + {registered, [ + couchbeam_sup + ]}, + {applications, [kernel, stdlib, crypto, public_key, ssl, sasl, + ibrowse]}, {env, []}, - {mod, { couchbeam_app, []}}]}. + {mod, { couchbeam_app, []}} + ] +}. diff --git a/src/couchbeam.erl b/src/couchbeam.erl index 0ffadbf1..29276169 100644 --- a/src/couchbeam.erl +++ b/src/couchbeam.erl @@ -6,20 +6,12 @@ -module(couchbeam). -author('BenoƮt Chesneau '). --behaviour(gen_server). - -include("couchbeam.hrl"). -define(TIMEOUT, infinity). --record(state, {}). % generic functions --export([start_link/0, start/0, stop/0, version/0]). - - -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +-export([start/0, stop/0, version/0]). %% utilities urls -export([server_url/1, uuids_url/1, db_url/1, doc_url/2, make_url/3]). @@ -57,48 +49,16 @@ %% Generic utilities. %% -------------------------------------------------------------------- -%%-------------------------------------------------------------------- -%% Function: start_link/0 -%% Description: Starts the server -%%-------------------------------------------------------------------- -%% @doc Starts the couchbeam process linked to the calling process. Usually -%% invoked by the supervisor couchbeam_sup -%% @spec start_link() -> {ok, pid()} -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -start_apps([]) -> - ok; -start_apps([App|Rest]) -> - case application:start(App) of - ok -> - start_apps(Rest); - {error, {already_started, App}} -> - start_apps(Rest); - {error, _Reason} when App =:= public_key -> - % ignore on R12B5 - start_apps(Rest); - {error, _Reason} -> - {error, {app_would_not_start, App}} - end. - - %% @doc Start the couchbeam process. Useful when testing using the shell. start() -> couchbeam_deps:ensure(), - case start_apps([crypto, public_key, sasl, ssl, ibrowse]) of - ok -> - couchbeam_sup:start_link(); - Error -> - Error - end. + application:load(couchbeam), + couchbeam_util:start_app_deps(couchbeam), + application:start(couchbeam). %% @doc Stop the couchbeam process. Useful when testing using the shell. stop() -> - application:stop(couchbeam), - application:stop(ibrowse), - application:stop(crypto). - + application:stop(couchbeam). %% @spec () -> Version %% Version = string() @@ -188,12 +148,13 @@ server_info(#server{options=IbrowseOpts}=Server) -> %% @doc Get one uuid from the server %% @spec get_uuid(server()) -> lists() get_uuid(Server) -> - get_uuids(Server, 1). + couchbeam_uuids:get_uuids(Server, 1). %% @doc Get a list of uuids from the server %% @spec get_uuids(server(), integer()) -> lists() get_uuids(Server, Count) -> - gen_server:call(?MODULE, {get_uuids, Server, Count}). + couchbeam_uuids:get_uuids(Server, Count). + %% @doc Handle replication. Pass an object containting all informations %% It allows to pass for example an authentication info @@ -908,7 +869,7 @@ maybe_docid(Server, {DocProps}) -> {DocProps} end. -%% @doc Assemble the server URL for the given client +%% @doc Asemble the server URL for the given client %% @spec server_url({Host, Port}) -> iolist() server_url(#server{host=Host, port=Port, options=Options}) -> Ssl = couchbeam_util:get_value(is_ssl, Options, false), @@ -965,77 +926,4 @@ db_request(Method, Url, Expect, Options, Headers, Body) -> Error end. -%%--------------------------------------------------------------------------- -%% gen_server callbacks -%%--------------------------------------------------------------------------- -%% @private - -init(_) -> - process_flag(trap_exit, true), - ets:new(couchbeam_uuids, [named_table, public, {keypos, 2}]), - {ok, #state{}}. - -handle_call({get_uuids, #server{host=Host, port=Port}=Server, Count}, _From, State) -> - {ok, Uuids} = do_get_uuids(Server, Count, [], - ets:lookup(couchbeam_uuids, {Host, Port})), - {reply, Uuids, State}. - - -handle_cast(_Msg, State) -> - {noreply, State}. - - -handle_info(_Info, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -do_get_uuids(_Server, Count, Acc, _) when length(Acc) >= Count -> - {ok, Acc}; -do_get_uuids(Server, Count, Acc, []) -> - {ok, ServerUuids} = get_new_uuids(Server), - do_get_uuids(Server, Count, Acc, [ServerUuids]); -do_get_uuids(Server, Count, Acc, [#server_uuids{uuids=Uuids}]) -> - case Uuids of - [] -> - {ok, ServerUuids} = get_new_uuids(Server), - do_get_uuids(Server, Count, Acc, [ServerUuids]); - _ -> - {Acc1, Uuids1} = do_get_uuids1(Acc, Uuids, Count), - #server{host=Host, port=Port} = Server, - ServerUuids = #server_uuids{host_port={Host,Port}, - uuids=Uuids1}, - ets:insert(couchbeam_uuids, ServerUuids), - do_get_uuids(Server, Count, Acc1, [ServerUuids]) - end. - - - -do_get_uuids1(Acc, Uuids, 0) -> - {Acc, Uuids}; -do_get_uuids1(Acc, [Uuid|Rest], Count) -> - do_get_uuids1([Uuid|Acc], Rest, Count-1). - - -get_new_uuids(Server=#server{host=Host, port=Port, options=IbrowseOptions}) -> - Url = make_url(Server, "_uuids", [{"count", "1000"}]), - case couchbeam_httpc:request(get, Url, ["200"], IbrowseOptions) of - {ok, _Status, _Headers, Body} -> - {[{<<"uuids">>, Uuids}]} = ejson:decode(Body), - ServerUuids = #server_uuids{host_port={Host, - Port}, uuids=Uuids}, - ets:insert(couchbeam_uuids, ServerUuids), - {ok, ServerUuids}; - Error -> - Error - end. - - diff --git a/src/couchbeam_app.erl b/src/couchbeam_app.erl index ece6425e..f54390c6 100644 --- a/src/couchbeam_app.erl +++ b/src/couchbeam_app.erl @@ -1,6 +1,6 @@ %%% -*- erlang -*- %%% -%%% This file is part of couchbeam released under the MIT license. +%%% This file is part of couchbeam released under the MIT license. %%% See the NOTICE for more information. -module(couchbeam_app). @@ -13,15 +13,15 @@ %% Func: start/2 %% Returns: {ok, Pid} | %% {ok, Pid, State} | -%% {error, Reason} +%% {error, Reason} %%-------------------------------------------------------------------- start(_Type, _StartArgs) -> - couchbeam_deps:ensure(), + couchbeam_util:start_app_deps(couchbeam), couchbeam_sup:start_link(). %%-------------------------------------------------------------------- %% Func: stop/1 -%% Returns: any +%% Returns: any %%-------------------------------------------------------------------- stop(_State) -> ok. diff --git a/src/couchbeam_sup.erl b/src/couchbeam_sup.erl index 679610e2..f3e14b13 100644 --- a/src/couchbeam_sup.erl +++ b/src/couchbeam_sup.erl @@ -1,6 +1,6 @@ %%% -*- erlang -*- %%% -%%% This file is part of couchbeam released under the MIT license. +%%% This file is part of couchbeam released under the MIT license. %%% See the NOTICE for more information. -module(couchbeam_sup). @@ -16,7 +16,8 @@ start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). init([]) -> - AChild = {couchbeam,{couchbeam,start_link,[]}, - permanent,2000,worker, [couchbeam]}, - - {ok, {{one_for_one, 3, 10}, [AChild]}}. + Uuids = {couchbeam_uuids, + {couchbeam_uuids, start_link, []}, + permanent,2000,worker, [couchbeam_uuids]}, + + {ok, {{one_for_one, 10, 3600}, [Uuids]}}. diff --git a/src/couchbeam_util.erl b/src/couchbeam_util.erl index 3e47d374..58e77453 100644 --- a/src/couchbeam_util.erl +++ b/src/couchbeam_util.erl @@ -13,6 +13,7 @@ -export([propmerge/3, propmerge1/2]). -export([get_value/2, get_value/3]). -export([deprecated/3, shutdown_sync/1]). +-export([start_app_deps/1, get_app_env/2]). -define(ENCODE_DOCID, true). @@ -214,3 +215,26 @@ shutdown_sync(Pid) -> after erlang:demonitor(MRef, [flush]) end. + +%% @spec start_app_deps(App :: atom()) -> ok +%% @doc Start depedent applications of App. +start_app_deps(App) -> + {ok, DepApps} = application:get_key(App, applications), + [ensure_started(A) || A <- DepApps], + ok. + +%% @spec ensure_started(Application :: atom()) -> ok +%% @doc Start the named application if not already started. +ensure_started(App) -> + case application:start(App) of + ok -> + ok; + {error, {already_started, App}} -> + ok + end. + +get_app_env(Env, Default) -> + case application:get_env(couch, Env) of + {ok, Val} -> Val; + undefined -> Default + end. diff --git a/src/couchbeam_uuids.erl b/src/couchbeam_uuids.erl new file mode 100644 index 00000000..3f4ec4aa --- /dev/null +++ b/src/couchbeam_uuids.erl @@ -0,0 +1,110 @@ +%%% -*- erlang -*- +%%% +%%% This file is part of couchbeam released under the MIT license. +%%% See the NOTICE for more information. + +-module(couchbeam_uuids). +-behaviour(gen_server). + +-export([start_link/0, get_uuids/2]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + + +-include("couchbeam.hrl"). + +-record(state, {}). + +%% @doc Get a list of uuids from the server +%% @spec get_uuids(server(), integer()) -> lists() +get_uuids(Server, Count) -> + gen_server:call(?MODULE, {get_uuids, Server, Count}). + + +%%-------------------------------------------------------------------- +%% Function: start_link/0 +%% Description: Starts the server +%%-------------------------------------------------------------------- +%% @doc Starts the couchbeam process linked to the calling process. Usually +%% invoked by the supervisor couchbeam_sup +%% @spec start_link() -> {ok, pid()} +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%%--------------------------------------------------------------------------- +%% gen_server callbacks +%%--------------------------------------------------------------------------- +%% @private + +init(_) -> + process_flag(trap_exit, true), + ets:new(couchbeam_uuids, [named_table, public, {keypos, 2}]), + {ok, #state{}}. + +handle_call({get_uuids, #server{host=Host, port=Port}=Server, Count}, + _From, State) -> + {ok, Uuids} = do_get_uuids(Server, Count, [], + ets:lookup(couchbeam_uuids, {Host, Port})), + {reply, Uuids, State}. + + +handle_cast(_Msg, State) -> + {noreply, State}. + + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +do_get_uuids(_Server, Count, Acc, _) when length(Acc) >= Count -> + {ok, Acc}; +do_get_uuids(Server, Count, Acc, []) -> + {ok, ServerUuids} = get_new_uuids(Server), + do_get_uuids(Server, Count, Acc, [ServerUuids]); +do_get_uuids(Server, Count, Acc, [#server_uuids{uuids=Uuids}]) -> + case Uuids of + [] -> + {ok, ServerUuids} = get_new_uuids(Server), + do_get_uuids(Server, Count, Acc, [ServerUuids]); + _ -> + {Acc1, Uuids1} = do_get_uuids1(Acc, Uuids, Count), + #server{host=Host, port=Port} = Server, + ServerUuids = #server_uuids{host_port={Host,Port}, + uuids=Uuids1}, + ets:insert(couchbeam_uuids, ServerUuids), + do_get_uuids(Server, Count, Acc1, [ServerUuids]) + end. + + + +do_get_uuids1(Acc, Uuids, 0) -> + {Acc, Uuids}; +do_get_uuids1(Acc, [Uuid|Rest], Count) -> + do_get_uuids1([Uuid|Acc], Rest, Count-1). + + +get_new_uuids(Server=#server{host=Host, port=Port, options=IbrowseOptions}) -> + Url = couchbeam:make_url(Server, "_uuids", [{"count", "1000"}]), + case couchbeam_httpc:request(get, Url, ["200"], IbrowseOptions) of + {ok, _Status, _Headers, Body} -> + {[{<<"uuids">>, Uuids}]} = ejson:decode(Body), + ServerUuids = #server_uuids{host_port={Host, + Port}, uuids=Uuids}, + ets:insert(couchbeam_uuids, ServerUuids), + {ok, ServerUuids}; + Error -> + Error + end. + + + diff --git a/t/002-server.t b/t/002-server.t index f30978b7..e6bd419f 100644 --- a/t/002-server.t +++ b/t/002-server.t @@ -2,7 +2,7 @@ %% -*- erlang -*- %%! -pa ./ebin -pa ./t %% -%% This file is part of couchbeam released under the MIT license. +%% This file is part of couchbeam released under the MIT license. %% See the NOTICE for more information. @@ -17,10 +17,10 @@ main(_) -> etap:bail() end, ok. - + test() -> - Server = couchbeam:server_connection(), + Server = couchbeam:server_connection(), {ok, {Data}} = couchbeam:server_info(Server), etap:is(proplists:get_value(<<"couchdb">>, Data), <<"Welcome">>, "message ok"), ok.