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(),