couchdb-erlang mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Binbin Wang <binbinwang...@gmail.com>
Subject Re: Learning Erlang/OTP and CouchDB internals together
Date Mon, 19 Nov 2012 07:27:40 GMT
Hi Dave,

Nice homework! Replying the question "1. how are configs loaded at startup
in CouchDB?"

Referring to the current master,
commit-d9566c831d002be16f866f0065a905bc23773cf9

Assuming we use the script ../couchdb/bin/couchdb -i to launch the couchdb
service
*command="/opt/couchdb/erlang/bin/erl $interactive_option
$ERL_START_OPTIONS \*
*  -env ERL_LIBS /opt/couchdb/couchdb/lib/couchdb/erlang/lib -couch_ini
$start_arguments -s couch"*

`*eval $command* -pidfile $PID_FILE -heart \
      >> $STDOUT_FILE 2>> $STDERR_FILE` || true

The script execute the $command to launch the couchdb service, moving to
the couch.erl
couch.erl
 17 start() ->
 *18     ok = application:start(couch).*

Let's checking the couch application in couch.app
  1 {application, couch, [
  2     {description, "@package_name@"},
  3     {vsn, "@version@"},
  4     {modules, [@modules@]},
  5     {registered, [
  6         couch_config,
  7         couch_db_update,
  8         couch_db_update_notifier_sup,
  9         couch_external_manager,
 10         couch_httpd,
 11         couch_log,
 12         couch_primary_services,
 13         couch_query_servers,
 14         couch_secondary_services,
 15         couch_server,
 16         couch_server_sup,
 17         couch_stats_aggregator,
 18         couch_stats_collector,
 19         couch_task_status
 20     ]},
* 21     {mod, {couch_app, [*
* 22         "%localconfdir%/@defaultini@",*
* 23         "%localconfdir%/@localini@"*
* 24     ]}},*
 25     {applications, [kernel, stdlib]},
 26     {included_applications, [crypto, sasl, inets, oauth, ibrowse,
mochiweb, os_mon]}
 27 ]}.

Check the line 21, 22, 23, 24, moving to the module couch_app.erl,
 21 start(_Type, DefaultIniFiles) ->
 22     *IniFiles = get_ini_files(DefaultIniFiles),*
 23     case start_apps([crypto, public_key, sasl, inets, oauth, ssl,
ibrowse, mochiweb, os_mon]) of
 24     ok ->
 25         *couch_server_sup:start_link(IniFiles);*
 26     {error, Reason} ->
 27         {error, Reason}
 28     end.

In my case, the IniFiles is actually,
["/opt/couchdb/couchdb/etc/couchdb/default.ini","/opt/couchdb/couchdb/etc/couchdb/local.ini"]

Move to the couch_server_sup.erl
 25 start_link(IniFiles) ->
 26     case whereis(couch_server_sup) of
 27     undefined ->
 28        * start_server(IniFiles);*
 29     _Else ->
 30         {error, already_started}
 31     end.

 44 start_server(IniFiles) ->
    ...
* 56     {ok, ConfigPid} = couch_config:start_link(IniFiles),*
    ...

the question *"1. how are configs loaded at startup in CouchDB?"* can be
learned here.
line 56 spawn the couchdb config process, return the config process pid -
ConfigPid

Let's move to the couch_config to dig more, and then back to the
couch_server_sub:start_server/1 later

couch_config.erl
 39 start_link(IniFiles) ->
 40     gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []).

  94 init(IniFiles) ->
* 95     ets:new(?MODULE, [named_table, set, protected]),*
 96     try
 97         lists:map(fun(IniFile) ->
* 98             {ok, ParsedIniValues} = parse_ini_file(IniFile),*
* 99             ets:insert(?MODULE, ParsedIniValues)*
100         end, IniFiles),
101         WriteFile = case IniFiles of
102             [_|_] -> lists:last(IniFiles);
103             _ -> undefined
104         end,
105         {ok, #config{write_filename = WriteFile}}
106     catch _Tag:Error ->
107         {stop, Error}
108     end.

The configuration in default.ini and local.ini are transformed into ets
table. The function couch_config:parse_ini_file/1 is actually to read the
file and parse the configs in the files.

Let's back to the couch_server_sub:start_server/1,
 72     BaseChildSpecs =
 73     {{one_for_all, 10, 3600},
 74         [{*couch_config,*
 75            * {couch_server_sup, couch_config_start_link_wrapper,
[IniFiles, ConfigPid]},*
 76             permanent,
 77             brutal_kill,
 78            * worker,*
 79             [couch_config]},
 80         {couch_primary_services,
 81             {couch_primary_sup, start_link, []},
 82             permanent,
 83             infinity,
 84             supervisor,
 85             [couch_primary_sup]},
 86         {couch_secondary_services,
 87             {couch_secondary_sup, start_link, []},
 88             permanent,
 89             infinity,
 90             supervisor,
 91             [couch_secondary_sup]}
 92         ]},

* 98     {ok, Pid} = supervisor:start_link(*
* 99         {local, couch_server_sup}, couch_server_sup, BaseChildSpecs),*

line 73~79, here the couch_config is actually a *child worker process* of
the couch_serer_sub (root in couchdb). The ConfigPid is actually the return
config process pid in line-56. Let's check the
couch_config_start_link_wrapper, which will link the config process pid if
it is alive, otherwise start the config process.

 36 couch_config_start_link_wrapper(IniFiles, FirstConfigPid) ->
 37     case is_process_alive(FirstConfigPid) of
 38         true ->
* 39             link(FirstConfigPid),*
 40             {ok, FirstConfigPid};
* 41         false -> couch_config:start_link(IniFiles)*
 42     end.

Regards & Thanks!
Binbin


2012/11/17 Dave Cottlehuber <dch@jsonified.com>

> Many thanks for all replies on my other thread!
>
> Erlang is amazing, and CouchDB obviously, but there's a big hurdle between
> the handful of erlang books, and real-world expert development.
>
> My (selfish!) original intent of asking for this list to be created was
> to use CouchDB as a convenient playground / reference point for improving
> my erlangz, and ultimately end up with some contributable code. And I
> hope that this approach will be a great thing for many of us in the
> same situation, and in the long term, also grow our community &
> committers too.
>
> So I am *really* keen for this to be as much of a group approach as
> possible,
> and spend time reviewing other's solutions etc, more so than just hacking
> away in a closet. We could set up a shared git repo if you all like, or
> just swap patches/gists over email. Whatever works.
>
> If you like the approach, the first one I suggest is about configuration,
> and we
> can check back in a week. I'd be rapt if this works out and others
> propose some topics along the way too.
>
> Homework :-)
>
> 1. how are configs loaded at startup in CouchDB?
> 2. how they're subsequently mutated/abused over the _config REST API?
> 3. how are these events managed elsewhere e.g. in couch httpd when IP
> changes?
> 4. compare with the sys.config approach used in OTP [1]
> 5. can you see a way to have the best of both worlds?
>
> I'll send my findings through early next week.
>
> A+
> Dave
>
> [1]: http://www.erlang.org/doc/design_principles/applications.html#id74029
>



-- 
Wang.bupt

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message