From 6b5676f0929b5f5da3e37e985484494bf3675b94 Mon Sep 17 00:00:00 2001 From: John Christopher Anderson Date: Fri, 10 Oct 2008 02:23:11 +0000 Subject: config web service fix from davisp git-svn-id: https://svn.apache.org/repos/asf/incubator/couchdb/trunk@703315 13f79535-47bb-0310-9956-ffa450edef68 --- share/www/script/couch_tests.js | 30 +++++++++++++ src/couchdb/couch_config.erl | 71 ++++++++++++++++++------------- src/couchdb/couch_httpd_misc_handlers.erl | 13 +++++- 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js index e88c68d1..0339dda6 100644 --- a/share/www/script/couch_tests.js +++ b/share/www/script/couch_tests.js @@ -1857,6 +1857,36 @@ var tests = { T(rows[(2*(i-4))+1].key == i+1); } T(db.view("test/single_doc").total_rows == 0); + }, + + config : function(debug) { + var db = new CouchDB("test_suite_db"); + db.deleteDb(); + db.createDb(); + if (debug) debugger; + + // test that /_config returns all the settings + var xhr = CouchDB.request("GET", "/_config"); + var config = JSON.parse(xhr.responseText); + T(config.couchdb.database_dir); + T(config.httpd.port == CouchDB.port); + T(config.daemons.httpd); + T(config.httpd_global_handlers._config); + T(config.log.level); + T(config.query_servers.javascript); + + // test that settings can be altered + xhr = CouchDB.request("PUT", "/_config/test/foo",{ + body : "bar" + }); + T(xhr.status == 200); + xhr = CouchDB.request("GET", "/_config/test"); + config = JSON.parse(xhr.responseText); + T(config.foo == "bar"); + + // you can get a single key + xhr = CouchDB.request("GET", "/_config/test/foo"); + T(xhr.responseText == '"bar"'); } }; diff --git a/src/couchdb/couch_config.erl b/src/couchdb/couch_config.erl index 8bce5718..f3b4f328 100644 --- a/src/couchdb/couch_config.erl +++ b/src/couchdb/couch_config.erl @@ -20,12 +20,8 @@ -include("couch_db.hrl"). -behaviour(gen_server). --export([start_link/1, init/1, - handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). --export([set/3, register/1, register/2, - get/1, get/2, get/3, - all/0, delete/2, load_ini_file/1]). +-export([start_link/1, init/1, handle_call/3, handle_cast/2, handle_info/2,terminate/2, code_change/3]). +-export([all/0, get/1, get/2, get/3, delete/2, set/3, register/1, register/2,load_ini_file/1]). -record(config, {notify_funs=[], @@ -36,32 +32,39 @@ %% @type etstable() = integer(). -start_link(IniFiles) -> gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []). +start_link(IniFiles) -> + gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []). +all() -> + gen_server:call(?MODULE, all). +get(Section) when is_binary(Section) -> + gen_server:call(?MODULE, {fetch, binary_to_list(Section)}); +get(Section) -> + gen_server:call(?MODULE, {fetch, Section}). +get(Section, Key) when is_binary(Section) and is_binary(Key) -> + get(binary_to_list(Section), binary_to_list(Key), undefined); +get(Section, Key) -> + get(Section, Key, undefined). +get(Section, Key, Default) when is_binary(Section) and is_binary(Key) -> + gen_server:call(?MODULE, {fetch, binary_to_list(Section), binary_to_list(Key), Default}); +get(Section, Key, Default) -> + gen_server:call(?MODULE, {fetch, Section, Key, Default}). + +set(Section, Key, Value) when is_binary(Section) and is_binary(Key) -> + gen_server:call(?MODULE, {set, [{{binary_to_list(Section), binary_to_list(Key)}, Value}]}); set(Section, Key, Value) -> gen_server:call(?MODULE, {set, [{{Section, Key}, Value}]}). +delete(Section, Key) when is_binary(Section) and is_binary(Key) -> + gen_server:call(?MODULE, {delete, {binary_to_list(Section), binary_to_list(Key)}}); delete(Section, Key) -> gen_server:call(?MODULE, {delete, {Section, Key}}). -get(Section, Key) -> - get(Section, Key, undefined). - -get(Section, Key, Default) -> - case ets:lookup(?MODULE, {Section, Key}) of - [] -> Default; - [{_,Result}] -> Result - end. - -get(Section) -> - Matches = ets:match(?MODULE, {{Section, '$1'}, '$2'}), - [{Key, Value} || [Key, Value] <- Matches]. - -all() -> gen_server:call(?MODULE, all). - -register(Fun) -> ?MODULE:register(Fun, self()). +register(Fun) -> + ?MODULE:register(Fun, self()). -register(Fun, Pid) -> gen_server:call(?MODULE, {register, Fun, Pid}). +register(Fun, Pid) -> + gen_server:call(?MODULE, {register, Fun, Pid}). %% Private API %% @@ -72,6 +75,20 @@ init(IniFiles) -> [ok = load_ini_file(IniFile) || IniFile <- IniFiles], {ok, #config{writeback_filename=lists:last(IniFiles)}}. +handle_call(all, _From, Config) -> + {reply, lists:sort(ets:tab2list(?MODULE)), Config}; + +handle_call({fetch, Section}, _From, Config) -> + Matches = ets:match(?MODULE, {{Section, '$1'}, '$2'}), + {reply, [{Key, Value} || [Key, Value] <- Matches], Config}; + +handle_call({fetch, Section, Key, Default}, _From, Config) -> + Ret = case ets:lookup(?MODULE, {Section, Key}) of + [] -> Default; + [{_,Result}] -> Result + end, + {reply, Ret, Config}; + handle_call({set, KVs}, _From, Config) -> [ok = insert_and_commit(Config, KV) || KV <- KVs], {reply, ok, Config}; @@ -80,16 +97,10 @@ handle_call({delete, Key}, _From, Config) -> ets:delete(?MODULE, Key), {reply, ok, Config}; -handle_call(all, _From, Config) -> - {reply, lists:sort(ets:tab2list(?MODULE)), Config}; - handle_call({register, Fun, Pid}, _From, #config{notify_funs=PidFuns}=Config) -> erlang:monitor(process, Pid), {reply, ok, Config#config{notify_funs=[{Pid, Fun}|PidFuns]}}. - - - %% @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. diff --git a/src/couchdb/couch_httpd_misc_handlers.erl b/src/couchdb/couch_httpd_misc_handlers.erl index 040e34de..8372c1b5 100644 --- a/src/couchdb/couch_httpd_misc_handlers.erl +++ b/src/couchdb/couch_httpd_misc_handlers.erl @@ -93,8 +93,17 @@ handle_uuids_req(Req) -> % GET /_config/ % GET /_config handle_config_req(#httpd{method='GET', path_parts=[_]}=Req) -> - KVs = [{list_to_binary(Key), list_to_binary(Value)} - || {Key, Value} <- couch_config:all()], + Grouped = lists:foldl(fun({{Section, Key}, Value}, Acc) -> + case dict:is_key(Section, Acc) of + true -> + dict:append(Section, {list_to_binary(Key), list_to_binary(Value)}, Acc); + false -> + dict:store(Section, [{list_to_binary(Key), list_to_binary(Value)}], Acc) + end + end, dict:new(), couch_config:all()), + KVs = dict:fold(fun(Section, Values, Acc) -> + [{list_to_binary(Section), {Values}} | Acc] + end, [], Grouped), send_json(Req, 200, {KVs}); % GET /_config/Section handle_config_req(#httpd{method='GET', path_parts=[_,Section]}=Req) -> -- cgit v1.2.3