diff options
-rw-r--r-- | etc/couchdb/default.ini.tpl.in | 2 | ||||
-rw-r--r-- | share/www/script/couch_tests.js | 33 | ||||
-rw-r--r-- | src/couchdb/couch_db.hrl | 8 | ||||
-rw-r--r-- | src/couchdb/couch_file_stats.erl | 2 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_misc_handlers.erl | 14 | ||||
-rw-r--r-- | src/couchdb/couch_server.erl | 55 | ||||
-rw-r--r-- | src/couchdb/couch_view.erl | 4 |
7 files changed, 83 insertions, 35 deletions
diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index e3600a9a..d16b1e71 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -7,6 +7,7 @@ database_dir = %localstatelibdir% util_driver_dir = %couchprivlibdir% max_document_size = 4294967296 ; 4 GB view_timeout = 5000 ; 5 seconds +max_dbs_open = 100 [httpd] port = 5984 @@ -39,6 +40,7 @@ favicon.ico = {couch_httpd_misc_handlers, handle_favicon_req, "%localdatadir%/ww _utils = {couch_httpd_misc_handlers, handle_utils_dir_req, "%localdatadir%/www"} _all_dbs = {couch_httpd_misc_handlers, handle_all_dbs_req} +_stats = {couch_httpd_misc_handlers, handle_stats_req} _config = {couch_httpd_misc_handlers, handle_config_req} _replicate = {couch_httpd_misc_handlers, handle_replicate_req} _uuids = {couch_httpd_misc_handlers, handle_uuids_req} diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js index de4f03db..dbdc27ce 100644 --- a/share/www/script/couch_tests.js +++ b/share/www/script/couch_tests.js @@ -2860,7 +2860,38 @@ var tests = { // Now delete document T(user2Db.deleteDoc(doc).ok); }); - } + }, + + + max_dbs_open : function(debug) { + if (debug) debugger; + restartServer(); + var max = 5; + run_on_modified_server( + [{section: "couchdb", + key: "max_dbs_open", + value: max.toString()}], + + function () { + for(var i=0; i<max*2; i++) { + var db = new CouchDB("test_suite_db"+ i); + db.deleteDb(); + db.createDb(); + } + + var stats = JSON.parse(CouchDB.request("GET", "/_stats").responseText); + T(stats.dbs_open == max); + + + for(var i=0; i<max*2; i++) { + var db = new CouchDB("test_suite_db"+ i); + db.deleteDb(); + } + + var stats = JSON.parse(CouchDB.request("GET", "/_stats").responseText); + T(stats.dbs_open == 0); + }) + }, }; function makeDocs(start, end, templateDoc) { diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl index 238025a2..d22d09c7 100644 --- a/src/couchdb/couch_db.hrl +++ b/src/couchdb/couch_db.hrl @@ -177,14 +177,6 @@ reduce_funs=[] }). --record(server,{ - root_dir = [], - dbname_regexp, - max_dbs_open=100, - current_dbs_open=0, - start_time="" - }). - -record(index_header, {seq=0, purge_seq=0, diff --git a/src/couchdb/couch_file_stats.erl b/src/couchdb/couch_file_stats.erl index 90ed973e..5e7d550b 100644 --- a/src/couchdb/couch_file_stats.erl +++ b/src/couchdb/couch_file_stats.erl @@ -30,7 +30,7 @@ track_file(Fd) -> get_stats() -> #stats{opened=Opened,closed=Closed}=gen_server:call(couch_file_stats,get), - {ok, [{opened,Opened}, {closed,Closed}]}. + [{files_open,Opened-Closed}, {files_closed,Closed}]. start_link() -> diff --git a/src/couchdb/couch_httpd_misc_handlers.erl b/src/couchdb/couch_httpd_misc_handlers.erl index c9a56c5c..5a1f6ee4 100644 --- a/src/couchdb/couch_httpd_misc_handlers.erl +++ b/src/couchdb/couch_httpd_misc_handlers.erl @@ -12,9 +12,9 @@ -module(couch_httpd_misc_handlers). --export([handle_welcome_req/2,handle_favicon_req/2,handle_utils_dir_req/2,handle_all_dbs_req/1, - handle_replicate_req/1,handle_restart_req/1,handle_uuids_req/1, - handle_config_req/1]). +-export([handle_welcome_req/2,handle_favicon_req/2,handle_utils_dir_req/2, + handle_all_dbs_req/1,handle_replicate_req/1,handle_restart_req/1, + handle_uuids_req/1,handle_config_req/1,handle_stats_req/1]). -export([increment_update_seq_req/2]). @@ -31,8 +31,7 @@ handle_welcome_req(#httpd{method='GET'}=Req, WelcomeMessage) -> send_json(Req, {[ {couchdb, WelcomeMessage}, - {version, list_to_binary(couch_server:get_version())}, - {start_time, list_to_binary(couch_server:get_start_time())} + {version, list_to_binary(couch_server:get_version())} ]}); handle_welcome_req(Req, _) -> send_method_not_allowed(Req, "GET,HEAD"). @@ -62,6 +61,11 @@ handle_all_dbs_req(#httpd{method='GET'}=Req) -> handle_all_dbs_req(Req) -> send_method_not_allowed(Req, "GET,HEAD"). +handle_stats_req(#httpd{method='GET'}=Req) -> + ok = couch_httpd:verify_is_server_admin(Req), + send_json(Req, {couch_server:get_stats() ++ couch_file_stats:get_stats()}); +handle_stats_req(Req) -> + send_method_not_allowed(Req, "GET,HEAD"). handle_replicate_req(#httpd{user_ctx=UserCtx,method='POST'}=Req) -> {Props} = couch_httpd:json_body(Req), diff --git a/src/couchdb/couch_server.erl b/src/couchdb/couch_server.erl index c576fc55..69cfa36c 100644 --- a/src/couchdb/couch_server.erl +++ b/src/couchdb/couch_server.erl @@ -18,10 +18,18 @@ -export([open/2,create/2,delete/2,all_databases/0,get_version/0]). -export([init/1, handle_call/3,sup_start_link/0]). -export([handle_cast/2,code_change/3,handle_info/2,terminate/2]). --export([dev_start/0,is_admin/2,has_admins/0,get_start_time/0]). +-export([dev_start/0,is_admin/2,has_admins/0,get_stats/0]). -include("couch_db.hrl"). +-record(server,{ + root_dir = [], + dbname_regexp, + max_dbs_open=100, + dbs_open=0, + start_time="" + }). + start() -> start(["default.ini"]). @@ -55,9 +63,10 @@ get_version() -> "0.0.0" end. -get_start_time() -> - {ok, #server{start_time=Time}} = gen_server:call(couch_server, get_server), - Time. +get_stats() -> + {ok, #server{start_time=Time,dbs_open=Open}} = + gen_server:call(couch_server, get_server), + [{start_time, ?l2b(Time)}, {dbs_open, Open}]. sup_start_link() -> gen_server:start_link({local, couch_server}, couch_server, [], []). @@ -124,16 +133,19 @@ init([]) -> RootDir = couch_config:get("couchdb", "database_dir", "."), MaxDbsOpen = list_to_integer( - couch_config:get("couchdb", "max_open_databases", "100")), + couch_config:get("couchdb", "max_dbs_open")), Self = self(), ok = couch_config:register( fun("couchdb", "database_dir") -> - exit(Self, config_change); - ("couchdb", "server_options") -> exit(Self, config_change) end), ok = couch_config:register( - fun("admins", _) -> + fun("couchdb", "max_dbs_open", Max) -> + gen_server:call(couch_server, + {set_max_dbs_open, list_to_integer(Max)}) + end), + ok = couch_config:register( + fun("admins") -> hash_admin_passwords() end), hash_admin_passwords(), @@ -164,13 +176,13 @@ all_databases() -> {ok, Filenames}. -maybe_close_lru_db(#server{current_dbs_open=NumOpen, max_dbs_open=MaxOpen}=Server) +maybe_close_lru_db(#server{dbs_open=NumOpen, max_dbs_open=MaxOpen}=Server) when NumOpen < MaxOpen -> {ok, Server}; -maybe_close_lru_db(#server{current_dbs_open=NumOpen}=Server) -> +maybe_close_lru_db(#server{dbs_open=NumOpen}=Server) -> % must free up the lru db. case try_close_lru(now()) of - ok -> {ok, Server#server{current_dbs_open=NumOpen-1}}; + ok -> {ok, Server#server{dbs_open=NumOpen-1}}; Error -> Error end. @@ -203,6 +215,8 @@ try_close_lru(StartTime) -> end end. +handle_call({set_max_dbs_open, Max}, _From, Server) -> + {reply, ok, Server#server{max_dbs_open=Max}}; handle_call(get_server, _From, Server) -> {reply, {ok, Server}, Server}; handle_call({open, DbName, Options}, _From, Server) -> @@ -220,9 +234,9 @@ handle_call({open, DbName, Options}, _From, Server) -> true = ets:insert(couch_dbs_by_name, {DbName, {MainPid, LruTime}}), true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}), true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}), - DbsOpen = Server2#server.current_dbs_open + 1, + DbsOpen = Server2#server.dbs_open + 1, {reply, {ok, MainPid}, - Server2#server{current_dbs_open=DbsOpen}}; + Server2#server{dbs_open=DbsOpen}}; Error -> {reply, Error, Server2} end; @@ -255,10 +269,10 @@ handle_call({create, DbName, Options}, _From, Server) -> {DbName, {MainPid, LruTime}}), true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}), true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}), - DbsOpen = Server2#server.current_dbs_open + 1, + DbsOpen = Server2#server.dbs_open + 1, couch_db_update_notifier:notify({created, DbName}), {reply, {ok, MainPid}, - Server2#server{current_dbs_open=DbsOpen}}; + Server2#server{dbs_open=DbsOpen}}; Error -> {reply, Error, Server2} end; @@ -285,8 +299,7 @@ handle_call({delete, DbName, _Options}, _From, Server) -> true = ets:delete(couch_dbs_by_name, DbName), true = ets:delete(couch_dbs_by_pid, Pid), true = ets:delete(couch_dbs_by_lru, LruTime), - DbsOpen = Server#server.current_dbs_open - 1, - Server#server{current_dbs_open=DbsOpen} + Server#server{dbs_open=Server#server.dbs_open - 1} end, case file:delete(FullFilepath) of ok -> @@ -306,13 +319,15 @@ handle_cast(Msg, _Server) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. - -handle_info({'EXIT', Pid, _Reason}, #server{current_dbs_open=DbsOpen}=Server) -> + +handle_info({'EXIT', _Pid, config_change}, _Server) -> + exit(kill); +handle_info({'EXIT', Pid, _Reason}, #server{dbs_open=DbsOpen}=Server) -> [{Pid, DbName}] = ets:lookup(couch_dbs_by_pid, Pid), [{DbName, {Pid, LruTime}}] = ets:lookup(couch_dbs_by_name, DbName), true = ets:delete(couch_dbs_by_pid, Pid), true = ets:delete(couch_dbs_by_name, DbName), true = ets:delete(couch_dbs_by_lru, LruTime), - {noreply, Server#server{current_dbs_open=DbsOpen-1}}; + {noreply, Server#server{dbs_open=DbsOpen-1}}; handle_info(Info, _Server) -> exit({unknown_message, Info}). diff --git a/src/couchdb/couch_view.erl b/src/couchdb/couch_view.erl index 5065b731..ce41dd23 100644 --- a/src/couchdb/couch_view.erl +++ b/src/couchdb/couch_view.erl @@ -20,6 +20,10 @@ extract_map_view/1]). -include("couch_db.hrl"). + + +-record(server,{ + root_dir = []}). start_link() -> gen_server:start_link({local, couch_view}, couch_view, [], []). |