Skip to content

Commit

Permalink
refactor uuids and change a little the way we start couchbeam.
Browse files Browse the repository at this point in the history
- create couchbeam_uuids module
- register couchbeam_sup module
- now app are started from the list given in applications key .
  • Loading branch information
benoitc committed Jan 8, 2012
1 parent 7b647da commit 3831813
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 137 deletions.
13 changes: 9 additions & 4 deletions 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, []}}
]
}.
130 changes: 9 additions & 121 deletions src/couchbeam.erl
Expand Up @@ -6,20 +6,12 @@
-module(couchbeam).
-author('Benoît Chesneau <benoitc@e-engura.org>').

-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]).
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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.



8 changes: 4 additions & 4 deletions 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).
Expand All @@ -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.
Expand Down
11 changes: 6 additions & 5 deletions 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).
Expand All @@ -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]}}.
24 changes: 24 additions & 0 deletions src/couchbeam_util.erl
Expand Up @@ -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).

Expand Down Expand Up @@ -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.
110 changes: 110 additions & 0 deletions 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.



0 comments on commit 3831813

Please sign in to comment.