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 <[email protected]>
> 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