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 09:13:42 GMT
Replying the question *"2. how they're subsequently mutated/abused over the
_config REST API?*". Does it means the codepath of the _config rest api? If
it is, the excellent explanation of Jan on the codepath of PUT /DB/DocID
will help to better understand other rest api, such as the  _config.

The five API related to _config as below,
GET     /_config
GET     /_config/section
GET     /_config/section/key
PUT     /_config/section/key
DELETE  /_config/section/key

Check the section [httpd_global_handlers] in default.ini
_config = {couch_httpd_misc_handlers, handle_config_req}

Moving to the couch_httpd_misc_handlers:handle_config_req/1. All five
_config apis are implemented here. By checking the code we can learn that
all five apis require the server admin role.

For both PUT and DELETE /_config/section/key, needing to check the
config_whitelist, if there is no config_whitelist, move to the function
couch_httpd_misc_handlers:handle_approved_config_req/2 to handle,

Regards & Thanks!
Binbin


2012/11/19 Binbin Wang <binbinwang118@gmail.com>

> 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
>



-- 
Wang.bupt

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