You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2008/08/16 18:01:39 UTC

svn commit: r686516 - in /incubator/couchdb/branches/runtimeconfig: src/couchdb/ test/

Author: damien
Date: Sat Aug 16 09:01:38 2008
New Revision: 686516

URL: http://svn.apache.org/viewvc?rev=686516&view=rev
Log:
Various changes and refactorings.

Modified:
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config_writer.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_httpd.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_log.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_query_servers.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server_sup.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_util.erl
    incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_view.erl
    incubator/couchdb/branches/runtimeconfig/test/couch_config_test.erl

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config.erl Sat Aug 16 09:01:38 2008
@@ -20,71 +20,41 @@
 -include("couch_db.hrl").
 
 -behaviour(gen_server).
--export([start_link/0, init/1, stop/0,
+-export([start_link/1, init/1,
     handle_call/3, handle_cast/2, handle_info/2, 
     terminate/2, code_change/3]).
--export([store/2, register/2, 
-    lookup/1, lookup/2,
-    lookup_match/1, lookup_match/2, 
-    lookup_and_register/2, lookup_and_register/3,
-    lookup_match_and_register/2, lookup_match_and_register/3,
-    dump/0, init_value/2, unset/1, load_ini_file/1, 
-    load_ini_files/1]).
+-export([store/2, register/1, register/2, 
+    get/1, get/2,
+    lookup_match/1, lookup_match/2,
+    dump/0, unset/1, load_ini_file/1]).
+    
+-record(config,
+    {notify_funs=[],
+    writeback_filename=""
+    }).
 
--define(COUCH_CONFIG_CALLBACK, "_CouchDBConfigChangeCallback").
 %% Public API %%
 
 %% @type etstable() = integer().
 
-%% @spec start_link() -> {ok, Tab::etsatable()}
-%% @doc Start the configuration module
-start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).    
-
-%% @spec stop() -> ok
-%% @doc Stops the configuration module
-stop() ->
-    ok.
-
-%% @spec init_value(Key::any(), Value::any()) -> {ok, Tab::etsatable()}
-%% @doc Public API function triggers initialization of a Key/Value pair. Used 
-%%      when setting values from the ini file. Works like store/2 but doesn't
-%%      write the Key/Value pair to the storage ini file.
-init_value(Key, Value) -> gen_server:call(?MODULE, {init_value, Key, Value}).
+start_link(IniFiles) -> gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []).  
 
 %% @spec store(Key::any(), Value::any()) -> {ok, Tab::etsatable()}
 %% @doc Public API function that triggers storage of a Key/Value pair into the
 %%      local ets table and writes it to the storage ini file.
 store(Key, Value) -> gen_server:call(?MODULE, {store, [{Key, Value}]}).
 
-%% @spec lookup(Key::any()) -> Value::any() | undefined
+%% @spec get(Key::any()) -> Value::any() | undefined
 %% @doc Returns the value that is stored under key::any() or undefined::atom() if no
 %%      such Key exists.
-lookup(Key) -> gen_server:call(?MODULE, {lookup, Key}).
+get(Key) ->
+    ?MODULE:get(Key, undefined).
 
-%% @spec lookup(Key::any(), Default::any()) -> Value::any() | Default
+%% @spec get(Key::any(), Default::any()) -> Value::any() | Default
 %% @doc Returns the value that is stored under key::any() or Default::any() if
 %%      no such Key exists.
-lookup(Key, Default) -> gen_server:call(?MODULE, {lookup, Key, Default}).
-
-%% @spec lookup_and_register(Key::any(), CallbackFunction::function()) ->
-%%         Value::any() | undefined
-%% @doc Returns the value that is stored under Key::any() or undefined::atom() if no
-%%      such Key exists. Additionally, this functions registers 
-%%      CallbackFunction::function() to be called if the value of Key::any()
-%%      is changed at a later point.
-lookup_and_register(Key, CallbackFunction) -> 
-    gen_server:call(?MODULE, {lookup_and_register, Key, CallbackFunction}).
-
-%% @spec lookup_and_register(
-%%         Key::any(),
-%%         Default::any(),
-%%         CallbackFunction::function()) -> Value::any() | Default
-%% @doc Returns the value that is stored under Key::any() or Default::any() if
-%%      such Key exists. Additionally, this functions registers 
-%%      CallbackFunction::function() to be called if the value of Key::any()
-%%      is changed at a later point.
-lookup_and_register(Key, Default, CallbackFunction) ->
-    gen_server:call(?MODULE, {lookup_and_register, Key, Default, CallbackFunction}).
+get(Key, Default) ->
+    fix_lookup_result(ets:lookup(?MODULE, Key), Default).
 
 %% @spec lookup_match(Key::any()) -> Value::any() | undefined:atom()
 %% @doc Lets you look for a Key's Value specifying a pattern that gets passed 
@@ -96,33 +66,15 @@
 %%      to ets::match(). Returns Default::any() if no Key is found
 lookup_match(Key, Default) -> gen_server:call(?MODULE, {lookup_match, Key, Default}).
 
-%% @spec lookup_match_and_register(Key::any(), CallbackFunction::function()) ->
-%%           Value::any() | undefined:atom()
-%% @doc Lets you look for a Key's Value specifying a pattern that gets passed 
-%%      to ets::match(). Returns undefined::atom() if no Key is found. Additionally,
-%%      this functions registers CallbackFunction::function() to be called if 
-%%      the value of Key::any() is changed at a later point.
-lookup_match_and_register(Key, CallbackFunction) ->
-    gen_server:call(?MODULE, {lookup_match_and_register, Key, CallbackFunction}).
-
-%% @spec lookup_match_and_register(
-%%           Key::any(), Default::any(), CallbackFunction::function()) ->
-%%               Value::any() | Default
-%% @doc Lets you look for a Key's Value specifying a pattern that gets passed 
-%%      to ets::match(). Returns undefined::atom() if no Key is found. Additionally,
-%%      this functions registers CallbackFunction::function() to be called if 
-%%      the value of Key::any() is changed at a later point.
-lookup_match_and_register(Key, Default, CallbackFunction) ->
-    gen_server:call(?MODULE, {lookup_match_and_register, Key, Default, CallbackFunction}).
-
 %% @spec dump() -> ok:atom()
 %% @doc Dumps the current ets table with all configuration data.
 dump() -> gen_server:call(?MODULE, {dump, []}).
 
-%% @spec register(Key::any(), Fun::function()) -> ok
-%% @doc Public API function that registers a function to be called when the
-%%      Value of Key::any() is changed.
-register(Key, Fun) -> gen_server:call(?MODULE, {register, Key, Fun}).
+
+register(Fun) -> gen_server:call(?MODULE, {register, Fun, self()}).
+
+
+register(Fun, Pid) -> gen_server:call(?MODULE, {register, Fun, Pid}).
 
 %% @spec unset(Key::any) -> ok
 %% @doc Public API call to remove the configuration entry from the internal 
@@ -133,161 +85,67 @@
 
 %% @spec init(List::list([])) -> {ok, Tab::etsatable()}
 %% @doc Creates a new ets table of the type "set".
-init([]) ->     
-    Tab = ets:new(?MODULE, [set]),
-    {ok, Tab}.
+init(IniFiles) ->
+    ets:new(?MODULE, [named_table, set, protected]),
+    [ok = load_ini_file(IniFile) || IniFile <- IniFiles],
+    
+    % announce startup
+    io:format("Apache CouchDB ~s (LogLevel=~s) is starting.~n", [
+        couch_server:get_version(),
+        ?MODULE:get({"Log", "Level"}, "info")
+    ]),
+    
+    {ok, #config{writeback_filename=lists:last(IniFiles)}}.
 
 %% @doc see store/2
-handle_call({store, Config}, _From, Tab) ->
-    [insert_and_commit(Tab, Config2) || Config2 <- Config],
-    {reply, ok, Tab};
+handle_call({store, KVs}, _From, Config) ->
+    [ok = insert_and_commit(Config, KV) || KV <- KVs],
+    {reply, ok, Config};
 
 
 %% @doc See init_value/2
-handle_call({init_value, Key, Value}, _From, Tab) ->
-    Reply = ets:insert(Tab, {Key, Value}),
-    {reply, Reply, Tab};
+handle_call({init_value, Key, Value}, _From, Config) ->
+    Reply = ets:insert(?MODULE, {Key, Value}),
+    {reply, Reply, Config};
 
 %% @doc See unset/1
-handle_call({unset, Key}, _From, Tab) ->
-    ets:delete(Tab, Key),
-    {reply, ok, Tab};
-
-
-%% @doc See lookup/1
-handle_call({lookup, Key}, _From, Tab) ->
-    lookup(Key, fun(Tab_, Key_) -> ets:lookup(Tab_, Key_) end, undefined, Tab);
-
-%% @doc See lookup/2
-handle_call({lookup, Key, Default}, _From, Tab) ->
-    lookup(Key, fun(Tab_, Key_) -> ets:lookup(Tab_, Key_) end, Default, Tab);
-
-%% @doc See lookup_and_register/2
-handle_call({lookup_and_register, Key, CallbackFunction}, _From, Tab) ->
-    ?MODULE:handle_call({register, Key, CallbackFunction}, _From, Tab),
-    lookup(Key, fun(Tab_, Key_) -> ets:lookup(Tab_, Key_) end, undefined, Tab);
-
-%% @doc See lookup_and_register/3
-handle_call({lookup_and_register, Key, Default, CallbackFunction}, _From, Tab) ->
-    ?MODULE:handle_call({register, Key, CallbackFunction}, _From, Tab),
-    lookup(Key, fun(Tab_, Key_) -> ets:lookup(Tab_, Key_) end, Default, Tab);
-
-%% @doc See lookup_match/1
-handle_call({lookup_match, Key}, _From, Tab) ->
-    lookup(Key, fun(Tab_, Key_) -> ets:match(Tab_, Key_) end, undefined, Tab);
+handle_call({unset, Key}, _From, Config) ->
+    ets:delete(?MODULE, Key),
+    {reply, ok, Config};
 
-%% @doc See lookup_match/2
-handle_call({lookup_match, Key, Default}, _From, Tab) ->
-    lookup(Key, fun(Tab_, Key_) -> ets:match(Tab_, Key_) end, Default, Tab);
 
-%% @doc See lookup_match_and_register/2
-handle_call({lookup_match_and_register, Key = {{Module, '$1'}, '$2'}, CallbackFunction}, _From, Tab) ->
-    ?MODULE:handle_call({register, {Module, ""}, CallbackFunction}, _From, Tab),
-    lookup(Key, fun(Tab_, Key_) -> ets:match(Tab_, Key_) end, undefined, Tab);
-
-%% @doc See lookup_match_and_register/3
-handle_call({lookup_match_and_register, Key = {{Module, '$1'}, '$2'}, Default, CallbackFunction}, _From, Tab) ->
-    ?MODULE:handle_call({register, {Module, ""}, CallbackFunction}, _From, Tab),
-    lookup(Key, fun(Tab_, Key_) -> ets:match(Tab_, Key_) end, Default, Tab);
+%% @doc See lookup_match/2
+handle_call({lookup_match, Key, Default}, _From, Config) ->
+    {reply, fix_lookup_result(ets:match(?MODULE, Key), Default), Config};
 
 %% @doc See dump/0
-handle_call({dump, []}, _From, Tab) ->
-    Config = lists:sort(ets:match(Tab, '$1')),
-    lists:foreach(fun([{{Module, Variable}, Value}]) ->
-        case Module of
-            ?COUCH_CONFIG_CALLBACK ->
-                ok; % ignore
-            _ ->
-                io:format("[~s] ~s=~p~n", [Module, Variable, Value])
-        end
-    end, Config),
-    {reply, ok, Tab};
+handle_call({dump, []}, _From, Config) ->
+    KVs = lists:sort(ets:tab2list(?MODULE)),
+    [io:format("[~s] ~s=~p~n", [Module, Variable, Value])
+            || {{Module, Variable}, Value} <- KVs],
+    {reply, ok, Config};
 
 %% @doc See register/2
-handle_call({register, Key, Fun}, From, Tab) ->
-    ets:insert(Tab, {{?COUCH_CONFIG_CALLBACK, Key}, {From, Fun}}),
-    {reply, ok, Tab}.
-
-%% @spec notify_registered_modules(
-%%           Tab::etstable(),
-%%           {{Module::string(), Variable::string()}, _Value::any()}) -> ok
-%% @doc Looks if a callback function exsists for the specified Module/Variable
-%%      combination and calls it.
-notify_registered_modules(Tab, {{Module, Variable}, _Value}) ->
-    % look for processes that registered for notifications for
-    % specific configuration variables
-    case ets:lookup(Tab, {?COUCH_CONFIG_CALLBACK, {Module, Variable}}) of
-        % found
-        [{{?COUCH_CONFIG_CALLBACK, {Module, Variable}}, {_From, Fun}}] ->
-            Fun();
-        _ -> % not found
-            ok
-    end,
+handle_call({register, Fun, Pid}, _From, #config{notify_funs=PidFuns}=Config) ->
+    erlang:monitor(process, Pid),
+    {reply, ok, Config#config{notify_funs=[{Pid, Fun}|PidFuns]}}.
     
-    % look for processes that registerd for notifications for
-    % entire modules. Their "Variable" value will be the empty string
-     case ets:lookup(Tab, {?COUCH_CONFIG_CALLBACK, {Module, ""}}) of
-        % found
-        [{{?COUCH_CONFIG_CALLBACK, {Module, _Variable}}, {_From2, Fun2}}] ->
-            Fun2();
-        _ -> % not found
-            ok
-    end.
-
-%% @spec lookup(Key::any(), Fun::function(), Default::any(), Tab::etstable()) ->
-%%           {reply, Reply::any(), Tab::etstable()}
-%% @doc Uses Fun to find the Value for Key. Returns Default if no Value can
-%%      be found. Fun is one of ets:lookup/2 and ets:match/2
-lookup(Key, Fun, Default, Tab) ->
-    Reply = case Fun(Tab, Key) of
-        [{Key, Value}] ->
-            {ok, Value};
-        [List] ->
-            {ok, lists:map(fun([Key2, Value2]) -> {Key2, Value2} end, [List])};
-        [] ->
-            case Default of
-                undefined ->
-                    {error, undefined};
-                _ ->
-                    {ok, Default}
-            end
-    end,
-    {reply, Reply, Tab}.
+
+fix_lookup_result([{_Key, Value}], _Default) ->
+    Value;
+fix_lookup_result([], Default) ->
+    Default;
+fix_lookup_result(Values, _Default) ->
+    [list_to_tuple(Value) || Value <- Values].
 
 %% @spec insert_and_commit(Tab::etstable(), Config::any()) -> ok
 %% @doc Inserts a Key/Value pair into the ets table, writes it to the storage 
 %%      ini file and calls all registered callback functions for Key.
-insert_and_commit(Tab, Config) ->
-    ets:insert(Tab, Config),
-    {reply, File, _Tab} = 
-        lookup({"_CouchDB", "ConfigurationStorageFile"}, 
-            fun(Tab_, Key_) -> ets:lookup(Tab_, Key_) end, 
-            undefined, Tab
-        ),
-        
-    notify_registered_modules(Tab, Config),
-    commit(Config, File).
-
-%% @spec commit(Config::any(), File::filename()) -> ok
-%% @doc Writes a Key/Value pair to the ini storage file.
-commit(Config, File) ->
-    case File of
-        {ok, FileName} ->
-            couch_config_writer:save_config(Config, FileName);
-        _ -> % silently ignore writing if we have only a single ini file
-            ok
-    end.
-
-%% @spec load_ini_files([File::filename()]) -> ok
-%% @doc Stores the last ini file in Files to be the storage ini file and
-%%      iterates over all ini files and calls load_ini_file/1 with each.
-load_ini_files(IniFiles) ->
-    % store the name of the last ini file for storing changes made at runtime
-    [LastIniFile|_] = lists:reverse(IniFiles),
-    ?MODULE:init_value({"_CouchDB", "ConfigurationStorageFile"}, LastIniFile),
-
-    % load all ini files in the order they come in.
-    lists:foreach(fun(IniFile) -> load_ini_file(IniFile) end, IniFiles).
+insert_and_commit(Config, KV) ->
+    true = ets:insert(?MODULE, KV),
+    % notify funs
+    %[catch Fun(KV) || {_Pid, Fun} <- Config#config.notify_funs],
+    couch_config_writer:save_to_file(KV, Config#config.writeback_filename).
 
 %% @spec load_ini_file(IniFile::filename()) -> ok
 %% @doc Parses an ini file and stores Key/Value Pairs into the ets table.
@@ -330,21 +188,19 @@
             end
         end, {"", []}, Lines),
         
-        lists:foreach(
-            fun({Key, Value}) ->
-                ?MODULE:init_value(Key, Value)
-            end,
-            lists:reverse(ParsedIniValues)
-        ),
+        [ets:insert(?MODULE, {Key, Value}) || {Key, Value} <- ParsedIniValues],
     ok.
 
 % Unused gen_server behaviour API functions that we need to declare.
 
 %% @doc Unused
-handle_cast(_Msg, State) -> {noreply, State}.
+handle_cast(foo, State) -> {noreply, State}.
 
-%% @doc Unused
-handle_info(_Msg, State) -> {noreply, State}.
+
+handle_info({'DOWN', _, _, DownPid, _}, #config{notify_funs=PidFuns}=Config) ->
+    % remove any funs registered by the downed process
+    FilteredPidFuns = [{Pid,Fun} || {Pid,Fun} <- PidFuns, Pid /= DownPid],
+    {noreply, Config#config{notify_funs=FilteredPidFuns}}.
 
 %% @doc Unused
 terminate(_Reason, _State) -> ok.

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config_writer.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config_writer.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config_writer.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_config_writer.erl Sat Aug 16 09:01:38 2008
@@ -19,13 +19,13 @@
 %% @see couch_config
 
 -module(couch_config_writer).
--export([save_config/2]).
+-export([save_to_file/2]).
 
-%% @spec save_config(
+%% @spec save_to_file(
 %%           Config::{{Module::string(), Variable::string()}, Value::string()}, 
 %%           File::filename()) -> ok
 %% @doc Saves a Module/Key/Value triple to the ini file File::filename()
-save_config({{Module, Variable}, Value}, File) ->
+save_to_file({{Module, Variable}, Value}, File) ->
     % open file and create a list of lines
     {ok, Stream} = file:read_file(File),
     {ok, Lines} = regexp:split(binary_to_list(Stream), "\r\n|\n|\r|\032"),

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_httpd.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_httpd.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_httpd.erl Sat Aug 16 09:01:38 2008
@@ -44,25 +44,31 @@
     
     % just stop if one of the config settings change. couch_server_sup
     % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction =  fun() -> couch_httpd:stop() end,
     
-    {ok, BindAddress} = couch_config:lookup_and_register(
-        {"HTTPd", "BindAddress"}, ConfigChangeCallbackFunction),
-    {ok, Port} = couch_config:lookup_and_register(
-        {"HTTPd", "Port"}, ConfigChangeCallbackFunction),
-    {ok, DocumentRoot} = couch_config:lookup_and_register(
-        {"HTTPd", "DocumentRoot"}, ConfigChangeCallbackFunction),
+    BindAddress = couch_config:get({"HTTPd", "BindAddress"}, "127.0.0.1"),
+    Port = couch_config:get({"HTTPd", "Port"}, "5984"),
+    DocumentRoot = couch_config:get({"HTTPd", "DocumentRoot"}, "../../share/www"),
     
     % and off we go
     Loop = fun (Req) -> apply(couch_httpd, handle_request, [Req, DocumentRoot]) end,
-    mochiweb_http:start([
+    {ok, Pid} = mochiweb_http:start([
         {loop, Loop},
         {name, ?MODULE},
         {ip, BindAddress},
         {port, Port}
-    ]).
+    ]),
+    ok = couch_config:register(
+        fun({"HTTPd", "BindAddress"}) ->
+            ?MODULE:stop();
+        ({"HTTPd", "Port"}) ->
+            ?MODULE:stop();
+        ({"HTTPd", "DocumentRoot"}) ->
+            ?MODULE:stop()
+        end, Pid),
+    {ok, Pid}.
 
 stop() ->
+    io:format("asfasfSZfasdfasdfasfasdf"),
     mochiweb_http:stop(?MODULE).
 
 handle_request(config_change) ->
@@ -833,32 +839,32 @@
     
 % GET /_config/Module/Key
 handle_config_request(Req, 'GET', {[Module, Key]}) ->
-    case couch_config:lookup({Module, Key}) of
-        {ok, Value} ->
-            send_json(Req, 200, {obj, [
-                {ok, true},
-                {module, Module},
-                {key, Key},
-                {value, Value}
-             ]});
-        undefined ->
-            throw({not_found, unkown_config_value})
+    case couch_config:get({Module, Key},null) of
+    null ->
+        throw({not_found, unknown_config_value});
+    Value ->
+        send_json(Req, 200, {obj, [
+            {ok, true},
+            {module, Module},
+            {key, Key},
+            {value, Value}
+         ]})
     end;
 
     
 % DELETE /_config/Key
 handle_config_request(Req, 'DELETE', {[Module, Key]}) ->
-    case couch_config:lookup({Module, Key}) of
-        {ok, OldValue} ->
-            couch_config:unset({Module, Key}),
-            send_json(Req, 200, {obj, [
-                {ok, true},
-                {module, Module},
-                {key, Key},
-                {old_value, OldValue}
-             ]});
-        undefined ->
-            throw({not_found, unkown_config_value})
+    case couch_config:get({Module, Key}, null) of
+    null ->
+        throw({not_found, unknown_config_value});
+    OldValue ->
+        couch_config:unset({Module, Key}),
+        send_json(Req, 200, {obj, [
+            {ok, true},
+            {module, Module},
+            {key, Key},
+            {old_value, OldValue}
+         ]})
     end.
 
 

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_log.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_log.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_log.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_log.erl Sat Aug 16 09:01:38 2008
@@ -35,22 +35,26 @@
 
 
 start_link() ->
+    couch_event_sup:start_link({local, couch_log}, error_logger, couch_log, []).
+
+stop() ->
+    couch_event_sup:stop(couch_log).
+
+init([]) ->
     % read config and register for configuration changes
     
     % just stop if one of the config settings change. couch_server_sup
     % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction =  fun() -> ?MODULE:stop() end,
-    {ok, Filename} = couch_config:lookup_and_register(
-        {"Log", "File"}, ConfigChangeCallbackFunction),
-    {ok, Level} = couch_config:lookup_and_register(
-        {"Log", "Level"}, info, ConfigChangeCallbackFunction),
-
-    couch_event_sup:start_link({local, couch_log}, error_logger, couch_log, {Filename, Level}).
-
-stop() ->
-    couch_event_sup:stop(couch_log).
+    ok = couch_config:register(
+        fun({"Log", "File"}) ->
+            ?MODULE:stop();
+        ({"Log", "Level"}) ->
+            ?MODULE:stop()
+        end),
+    
+    Filename = couch_config:get({"Log", "File"}, "log.txt"),
+    Level = couch_config:get({"Log", "Level"},"info"),
 
-init({Filename, Level}) ->
     {ok, Fd} = file:open(Filename, [append]),
     {ok, {Fd, level_integer(list_to_atom(Level))}}.
 

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_query_servers.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_query_servers.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_query_servers.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_query_servers.erl Sat Aug 16 09:01:38 2008
@@ -22,26 +22,8 @@
 
 -include("couch_db.hrl").
 
-timeout() ->
-    {ok, QueryTimeout} = couch_config:lookup(
-            {"CouchDB Query Server Options", "QueryTimeout"}, "5000"), % 5 secs
-    list_to_integer(QueryTimeout).
-
 start_link() ->
-    % read config and register for configuration changes
-    
-    % just stop if one of the config settings change. couch_server_sup
-    % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction =  fun() -> ?MODULE:stop() end,
-    
-    {ok, QueryServerList} = couch_config:lookup_match_and_register(
-        {{"CouchDB Query Servers", '$1'}, '$2'}, [],
-        ConfigChangeCallbackFunction),
-    couch_config:register(
-        {"CouchDB Query Server Options", "QueryTimeout"},
-        ConfigChangeCallbackFunction),
-
-    gen_server:start_link({local, couch_query_servers}, couch_query_servers, QueryServerList, []).
+    gen_server:start_link({local, couch_query_servers}, couch_query_servers, [], []).
 
 stop() ->
     exit(whereis(couch_query_servers), close).
@@ -50,6 +32,14 @@
     readline(Port, []).
 
 readline(Port, Acc) ->
+    
+    case get(query_server_timeout) of
+    undefined ->
+        Timeout = list_to_integer(couch_config:get(
+            {"CouchDB Query Server Options", "QueryTimeout"}, "5000")),
+        put(timeout, Timeout);
+    Timeout -> ok
+    end,
     receive
     {Port, {data, {noeol, Data}}} ->
         readline(Port, [Data|Acc]);
@@ -58,7 +48,7 @@
     {Port, Err} ->
         catch port_close(Port),
         throw({map_process_error, Err})
-    after timeout() ->
+    after Timeout ->
         catch port_close(Port),
         throw({map_process_error, "map function timed out"})
     end.
@@ -180,7 +170,19 @@
     {ok, tuple_to_list(Results)}.
 
 
-init(QueryServerList) ->
+init([]) ->
+    
+    % read config and register for configuration changes
+    
+    % just stop if one of the config settings change. couch_server_sup
+    % will restart us and then we will pick up the new settings.
+    QueryServerList = couch_config:lookup_match(
+            {{"CouchDB Query Servers", '$1'}, '$2'}, []),
+    ok = couch_config:register(
+        fun({"CouchDB Query Server" ++ _, _}) ->
+            ?MODULE:stop()
+        end),
+        
     {ok, {QueryServerList, []}}.
 
 terminate(_Reason, _Server) ->

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server.erl Sat Aug 16 09:01:38 2008
@@ -31,7 +31,7 @@
     }).
 
 start() ->
-    start([]).
+    start(["couch.ini"]).
 
 start(IniFiles) ->
     couch_server_sup:start_link(IniFiles).
@@ -64,18 +64,7 @@
     end.
 
 sup_start_link() ->
-    % read config and register for configuration changes
-    
-    % just stop if one of the config settings change. couch_server_sup
-    % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction =  fun() -> ?MODULE:stop() end,
-
-    {ok, RootDir} = couch_config:lookup_and_register(
-        {"CouchDB", "RootDirectory"}, ConfigChangeCallbackFunction),
-    {ok, Options} = couch_config:lookup_and_register(
-        {"CouchDB", "ServerOptions"}, [], ConfigChangeCallbackFunction),
-
-    gen_server:start_link({local, couch_server}, couch_server, {RootDir, Options}, []).
+    gen_server:start_link({local, couch_server}, couch_server, [], []).
 
 open(DbName, Options) ->
     gen_server:call(couch_server, {open, DbName, Options}).
@@ -100,7 +89,21 @@
 get_full_filename(Server, DbName) ->
     filename:join([Server#server.root_dir, "./" ++ DbName ++ ".couch"]).
 
-init({RootDir, Options}) ->
+init([]) ->
+    % read config and register for configuration changes
+    
+    % just stop if one of the config settings change. couch_server_sup
+    % will restart us and then we will pick up the new settings.
+
+    RootDir = couch_config:get({"CouchDB", "RootDirectory"}, "."),
+    Options = couch_config:get({"CouchDB", "ServerOptions"}, []),
+    Self = self(),
+    ok = couch_config:register(
+        fun({"CouchDB", "RootDirectory"}) ->
+            exit(Self, config_change);
+        ({"CouchDB", "ServerOptions"}) ->
+            exit(Self, config_change)
+        end),
     {ok, RegExp} = regexp:parse("^[a-z][a-z0-9\\_\\$()\\+\\-\\/]*$"),
     ets:new(couch_dbs_by_name, [set, private, named_table]),
     ets:new(couch_dbs_by_pid, [set, private, named_table]),

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server_sup.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server_sup.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server_sup.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_server_sup.erl Sat Aug 16 09:01:38 2008
@@ -14,7 +14,7 @@
 -behaviour(supervisor).
 
 
--export([start_link/1,stop/0]).
+-export([start_link/1,stop/0,couch_config_start_link_wrapper/2]).
 
 -include("couch_db.hrl").
 
@@ -24,14 +24,20 @@
 start_link(IniFiles) ->
     case whereis(couch_server_sup) of
     undefined ->
-        couch_config:start_link(),
-        couch_config:load_ini_files(IniFiles),
-        start_server();
+        start_server(IniFiles);
     _Else ->
         {error, already_started}
     end.
 
-start_server() ->
+couch_config_start_link_wrapper(IniFiles, FirstConfigPid) ->
+    case is_process_alive(FirstConfigPid) of
+        true ->
+            link(FirstConfigPid),
+            {ok, FirstConfigPid};
+        false -> couch_config:start_link(IniFiles)
+    end.
+
+start_server(IniFiles) ->
     case init:get_argument(pidfile) of
     {ok, [PidFile]} ->
         case file:write_file(PidFile, os:getpid()) of
@@ -40,29 +46,26 @@
         end;
     _ -> ok
     end,
+    {ok, ConfigPid} = couch_config:start_link(IniFiles),
+    
+    LibDir =
+    case couch_config:get({"CouchDB", "UtilDriverDir"}, null) of
+    null ->
+        filename:join(code:priv_dir(couch), "lib");
+    LibDir0 -> LibDir0
+    end,
+    
+    ok = couch_util:start_driver(LibDir),
 
-    % annoucne startup
-    {ok, LogLevel} = couch_config:lookup({"Log", "Level"}),
-    io:format("Apache CouchDB ~s (LogLevel=~s) is starting.~n", [
-        couch_server:get_version(),
-        LogLevel
-    ]),
-
-    % read config and register for configuration changes
-
-    % just stop if one of the config settings change. couch_server_sup
-    % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction = fun() -> ?MODULE:stop() end,
-    {ok, UpdateNotificationProcesses} = couch_config:lookup({"CouchDB", "UpdateNotificationProcesses"}, []),
-    {ok, FtSearchQueryServer} = couch_config:lookup({"Search", "QueryServer"}, []),
-
-    couch_config:register(
-        {"CouchDB", "UpdateNotificationProcesses"}, ConfigChangeCallbackFunction),
-    couch_config:register(
-        {"Search", "QueryServer"}, ConfigChangeCallbackFunction),
-
+    
     ChildProcesses =
-        [{couch_log,
+        [{couch_config,
+            {couch_server_sup, couch_config_start_link_wrapper, [IniFiles, ConfigPid]},
+            permanent,
+            brutal_kill,
+            worker,
+            [couch_config]},
+        {couch_log,
             {couch_log, start_link, []},
             permanent,
             brutal_kill,
@@ -98,60 +101,34 @@
             1000,
             supervisor,
             [couch_httpd]}
-        ] ++
-        lists:map(fun(UpdateNotificationProcess) when is_list(UpdateNotificationProcesses) ->
-            {UpdateNotificationProcess,
-                {couch_db_update_notifier, start_link, [UpdateNotificationProcess]},
-                permanent,
-                1000,
-                supervisor,
-                [couch_db_update_notifier]}
-            end, UpdateNotificationProcesses)
-        ++
-        case FtSearchQueryServer of
-        "" ->
-            [];
-        _ ->
-            [{couch_ft_query,
-                {couch_ft_query, start_link, [FtSearchQueryServer]},
-                permanent,
-                1000,
-                supervisor,
-                [couch_ft_query]}]
-        end,
-
-    % launch the icu bridge
-    couch_util:start_driver(),
+        ],
+   
 
     % ensure these applications are running
     application:start(inets),
     application:start(crypto),
 
-    process_flag(trap_exit, true),
-    StartResult = (catch supervisor:start_link(
-        {local, couch_server_sup}, couch_server_sup, ChildProcesses)),
-
-    {ok, BindAddress} = couch_config:lookup_and_register(
-        {"HTTPd", "BindAddress"}, ConfigChangeCallbackFunction),
-    {ok, Port} = couch_config:lookup_and_register(
-        {"HTTPd", "Port"}, ConfigChangeCallbackFunction),
-
-    case StartResult of
-    {ok,_} ->
-        % only output when startup was successful
-        io:format("Apache CouchDB has started, see http://~s:~s/_utils/index.html~n",
-            [BindAddress, Port]);
-    _ ->
-        % Since we failed startup, unconditionally dump configuration data to console
-        ok = couch_config:dump()
-    end,
-    process_flag(trap_exit, false),
-    StartResult.
+    {ok, Pid} = supervisor:start_link(
+        {local, couch_server_sup}, couch_server_sup, ChildProcesses),
+    io:format("started"),
+    % launch the icu bridge
+    % just restart if one of the config settings change.
+
+    couch_config:register(
+        fun({"CouchDB", "UtilDriverDir"}) ->
+            ?MODULE:stop()
+        end, Pid),
+    
+    % we only get where when startup was successful
+    BindAddress = couch_config:get({"HTTPd", "BindAddress"}),
+    Port = couch_config:get({"HTTPd", "Port"}),
+    io:format("Apache CouchDB has started, see http://~s:~s/_utils/index.html~n",
+            [BindAddress, Port]),
+    {ok, Pid}.
+
 
 stop() ->
-    catch exit(whereis(couch_server_sup), normal),
-    couch_config:stop(),
-    couch_log:stop().
+    catch exit(whereis(couch_server_sup), normal).
 
 init(ChildProcesses) ->
     {ok, {{one_for_one, 10, 3600}, ChildProcesses}}.

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_util.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_util.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_util.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_util.erl Sat Aug 16 09:01:38 2008
@@ -12,7 +12,7 @@
 
 -module(couch_util).
 
--export([start_driver/0]).
+-export([start_driver/1]).
 -export([should_flush/0, should_flush/1]).
 -export([new_uuid/0, rand32/0, implode/2, collate/2, collate/3]).
 -export([abs_pathname/1,abs_pathname/2, trim/1, ascii_lower/1]).
@@ -22,22 +22,9 @@
 % arbitrarily chosen amount of memory to use before flushing to disk
 -define(FLUSH_MAX_MEM, 10000000).
 
-start_driver() ->
+start_driver(LibDir) ->
     % read config and register for configuration changes
     
-    % just stop if one of the config settings change. couch_server_sup
-    % will restart us and then we will pick up the new settings.
-    ConfigChangeCallbackFunction =  fun() -> couch_server:stop(couch_config_change) end,
-    
-    {ok, LibDir1} = couch_config:lookup_and_register(
-        {"CouchDB", "UtilDriverDir"}, ConfigChangeCallbackFunction, none),
-    case LibDir1 of
-        none ->
-            LibDir = filename:join(code:priv_dir(couch), "lib");
-        _ ->
-            LibDir = LibDir1
-    end,
-
     case erl_ddll:load_driver(LibDir, "couch_erl_driver") of
     ok -> ok;
     {error, already_loaded} -> ok;

Modified: incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_view.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_view.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_view.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/src/couchdb/couch_view.erl Sat Aug 16 09:01:38 2008
@@ -14,7 +14,7 @@
 -behaviour(gen_server).
 
 -export([start_link/0,fold/4,fold/5,less_json/2, start_update_loop/3, start_temp_update_loop/5]).
--export([init/1,terminate/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,code_change/3]).
+-export([init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,code_change/3]).
 -export([get_reduce_view/1, get_map_view/1,get_row_count/1,reduce_to_count/1, fold_reduce/7]).
 
 -include("couch_db.hrl").
@@ -44,12 +44,7 @@
     }).
 
 start_link() ->
-    
-    % read configuration settings and register for configuration changes
-    {ok, RootDir} = couch_config:lookup_and_register(
-        {"CouchDB", "RootDirectory"}, fun() -> terminate(config_change) end),
-    
-    gen_server:start_link({local, couch_view}, couch_view, RootDir, []).
+    gen_server:start_link({local, couch_view}, couch_view, [], []).
 
 get_temp_updater(DbName, Type, MapSrc, RedSrc) ->
     {ok, Pid} = gen_server:call(couch_view, {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
@@ -202,7 +197,15 @@
     {ok, _AccResult} = couch_btree:fold(Btree, StartKey, Dir, Fun, Acc).
 
 
-init(RootDir) ->
+init([]) ->
+    % read configuration settings and register for configuration changes
+    RootDir = couch_config:get({"CouchDB", "RootDirectory"}),
+    Self = self(),
+    ok = couch_config:register(
+        fun({"CouchDB", "RootDirectory"})->
+            exit(Self, config_change)
+        end),
+        
     couch_db_update_notifier:start_link(
         fun({deleted, DbName}) ->
             gen_server:cast(couch_view, {reset_indexes, DbName});
@@ -218,10 +221,7 @@
     process_flag(trap_exit, true),
     {ok, #server{root_dir=RootDir}}.
 
-terminate(Reason, _) ->
-    terminate(Reason).
-
-terminate(_Reason) ->
+terminate(_Reason,_State) ->
     ok.
 
 

Modified: incubator/couchdb/branches/runtimeconfig/test/couch_config_test.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/runtimeconfig/test/couch_config_test.erl?rev=686516&r1=686515&r2=686516&view=diff
==============================================================================
--- incubator/couchdb/branches/runtimeconfig/test/couch_config_test.erl (original)
+++ incubator/couchdb/branches/runtimeconfig/test/couch_config_test.erl Sat Aug 16 09:01:38 2008
@@ -33,7 +33,7 @@
     couch_config:start_link(),
 
     couch_config:init_value(Key, Value),
-    {ok, Result} = couch_config:lookup(Key),
+    Result = couch_config:get(Key),
     couch_config:unset(Key),
 
     couch_config:stop(),