You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ja...@apache.org on 2009/02/22 14:50:38 UTC

svn commit: r746691 - in /couchdb/trunk: etc/couchdb/ share/ share/www/script/ src/couchdb/

Author: jan
Date: Sun Feb 22 13:50:38 2009
New Revision: 746691

URL: http://svn.apache.org/viewvc?rev=746691&view=rev
Log:
Add runtime statistics -- without EUnit tests for now.

Modified:
    couchdb/trunk/etc/couchdb/default.ini.tpl.in
    couchdb/trunk/share/Makefile.am
    couchdb/trunk/share/www/script/couch.js
    couchdb/trunk/share/www/script/couch_test_runner.js
    couchdb/trunk/share/www/script/couch_tests.js
    couchdb/trunk/src/couchdb/Makefile.am
    couchdb/trunk/src/couchdb/couch_httpd.erl
    couchdb/trunk/src/couchdb/couch_httpd_db.erl
    couchdb/trunk/src/couchdb/couch_httpd_misc_handlers.erl
    couchdb/trunk/src/couchdb/couch_httpd_view.erl
    couchdb/trunk/src/couchdb/couch_server.erl
    couchdb/trunk/src/couchdb/couch_server_sup.erl

Modified: couchdb/trunk/etc/couchdb/default.ini.tpl.in
URL: http://svn.apache.org/viewvc/couchdb/trunk/etc/couchdb/default.ini.tpl.in?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/etc/couchdb/default.ini.tpl.in (original)
+++ couchdb/trunk/etc/couchdb/default.ini.tpl.in Sun Feb 22 13:50:38 2009
@@ -35,6 +35,8 @@
 db_update_notifier={couch_db_update_notifier_sup, start_link, []}
 query_servers={couch_query_servers, start_link, []}
 httpd={couch_httpd, start_link, []}
+stats_aggregator={couch_stats_aggregator, start, []}
+stats_collector={couch_stats_collector, start, []}
 
 [httpd_global_handlers]
 / = {couch_httpd_misc_handlers, handle_welcome_req, <<"Welcome">>}
@@ -42,12 +44,12 @@
 
 _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}
 _active_tasks = {couch_httpd_misc_handlers, handle_task_status_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}
 _restart = {couch_httpd_misc_handlers, handle_restart_req}
+_stats = {couch_httpd_stats_handlers, handle_stats_req}
 
 [httpd_db_handlers]
 _view = {couch_httpd_view, handle_view_req}

Modified: couchdb/trunk/share/Makefile.am
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/Makefile.am?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/share/Makefile.am (original)
+++ couchdb/trunk/share/Makefile.am Sun Feb 22 13:50:38 2009
@@ -112,5 +112,4 @@
     www/script/test/purge.js \
     www/script/test/config.js \
     www/script/test/security_validation.js \
-    www/script/test/max_dbs_open.js \
     www/style/layout.css

Modified: couchdb/trunk/share/www/script/couch.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch.js?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/couch.js [utf-8] Sun Feb 22 13:50:38 2009
@@ -312,6 +312,23 @@
   return req;
 }
 
+CouchDB.requestStats = function(module, key, aggregate, options) {
+  var options, optionsOrLast = Array.prototype.pop.apply(arguments);
+  if (typeof optionsOrLast == "string") {
+    options = null;
+    Array.prototype.push.apply(arguments, [optionsOrLast]);
+  } else {
+    options = optionsOrLast;
+  }
+
+  var request_options = {};
+  request_options.headers = {"Content-Type": "application/json"};
+
+  var stat = CouchDB.request("GET", "/_stats/" + Array.prototype.join.apply(arguments,["/"]) + (options ?
+    ("?" + CouchDB.params(options)) : ""), request_options).responseText;
+  return JSON.parse(stat)[module][key];
+}
+
 CouchDB.uuids_cache = [];
 
 CouchDB.newUuids = function(n) {
@@ -344,3 +361,13 @@
     throw result;
   }
 }
+
+CouchDB.params = function(options) {
+  options = options || {};
+  var returnArray = [];
+  for(var key in options) {
+    var value = options[key];
+    returnArray.push(key + "=" + value);
+  }
+  return returnArray.join("&");
+}
\ No newline at end of file

Modified: couchdb/trunk/share/www/script/couch_test_runner.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_test_runner.js?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_test_runner.js (original)
+++ couchdb/trunk/share/www/script/couch_test_runner.js Sun Feb 22 13:50:38 2009
@@ -152,13 +152,13 @@
 // display the line that failed.
 // Example:
 // T(MyValue==1);
-function T(arg1, arg2) {
+function T(arg1, arg2, testName) {
   if (!arg1) {
     if (currentRow) {
       if ($("td.details ol", currentRow).length == 0) {
         $("<ol></ol>").appendTo($("td.details", currentRow));
       }
-      $("<li><b>Assertion failed:</b> <code class='failure'></code></li>")
+      $("<li><b>Assertion " + (testName ? "'" + testName + "'" : "") + " failed:</b> <code class='failure'></code></li>")
         .find("code").text((arg2 != null ? arg2 : arg1).toString()).end()
         .appendTo($("td.details ol", currentRow));
     }
@@ -166,6 +166,10 @@
   }
 }
 
+function TEquals(expected, actual, testName) {
+  T(equals(expected, actual), "expected '" + expected + "', got '" + actual + "'", testName);
+}
+
 function equals(a,b) {
   if (a === b) return true;
   try {

Modified: couchdb/trunk/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_tests.js?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/couch_tests.js [utf-8] Sun Feb 22 13:50:38 2009
@@ -66,7 +66,6 @@
 loadTest("purge.js");
 loadTest("config.js");
 loadTest("security_validation.js");
-loadTest("max_dbs_open.js");
 
 function makeDocs(start, end, templateDoc) {
   var templateDocSrc = templateDoc ? JSON.stringify(templateDoc) : "{}"

Modified: couchdb/trunk/src/couchdb/Makefile.am
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/Makefile.am?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/Makefile.am (original)
+++ couchdb/trunk/src/couchdb/Makefile.am Sun Feb 22 13:50:38 2009
@@ -58,6 +58,7 @@
     couch_httpd_show.erl \
     couch_httpd_view.erl \
     couch_httpd_misc_handlers.erl \
+    couch_httpd_stats_handlers.erl \
     couch_key_tree.erl \
     couch_log.erl \
     couch_os_process.erl \
@@ -66,6 +67,8 @@
     couch_rep.erl \
     couch_server.erl \
     couch_server_sup.erl \
+    couch_stats_aggregator.erl \
+    couch_stats_collector.erl \
     couch_stream.erl \
     couch_task_status.erl \
     couch_util.erl \
@@ -96,6 +99,7 @@
     couch_httpd_show.beam \
     couch_httpd_view.beam \
     couch_httpd_misc_handlers.beam \
+    couch_httpd_stats_handlers.beam \
     couch_key_tree.beam \
     couch_log.beam \
     couch_os_process.beam \
@@ -104,6 +108,8 @@
     couch_rep.beam \
     couch_server.beam \
     couch_server_sup.beam \
+    couch_stats_aggregator.beam \
+    couch_stats_collector.beam \
     couch_stream.beam \
     couch_task_status.beam \
     couch_util.beam \
@@ -152,7 +158,7 @@
 # $(ERL) -noshell -run edoc_run files [\"$<\"]
 
 %.beam: %.erl couch_db.hrl
-	$(ERLC) $<
+	$(ERLC) ${TEST} $<;
 
 install-data-hook:
 	if test -f "$(DESTDIR)/$(couchprivlibdir)/couch_erl_driver"; then \

Modified: couchdb/trunk/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd.erl Sun Feb 22 13:50:38 2009
@@ -102,6 +102,7 @@
     
 
 handle_request(MochiReq, UrlHandlers, DbUrlHandlers) ->
+    statistics(runtime), % prepare request_time counter, see end of function
     AuthenticationFun = make_arity_1_fun(
             couch_config:get("httpd", "authentication_handler")),
     % for the path, use the raw path with the query string and fragment
@@ -123,11 +124,8 @@
         mochiweb_headers:to_list(MochiReq:get(headers))
     ]),
     
-    Method =
+    Method1 =
     case MochiReq:get(method) of
-        % alias HEAD to GET as mochiweb takes care of stripping the body
-        'HEAD' -> 'GET';
-        
         % already an atom
         Meth when is_atom(Meth) -> Meth;
         
@@ -135,6 +133,15 @@
         % possible (if any module references the atom, then it's existing).
         Meth -> couch_util:to_existing_atom(Meth)
     end,
+    
+    increment_method_stats(Method1),
+    
+    % alias HEAD to GET as mochiweb takes care of stripping the body
+    Method = case Method1 of
+        'HEAD' -> 'GET';
+        Other -> Other
+    end,
+
     HttpReq = #httpd{
         mochi_req = MochiReq,
         method = Method,
@@ -163,8 +170,14 @@
         RawUri,
         Resp:get(code)
     ]),
+    {_TotalRuntime, RequestTime} = statistics(runtime),
+    couch_stats_collector:record({couchdb, request_time}, RequestTime),
+    couch_stats_collector:increment({httpd, requests}),
     {ok, Resp}.
 
+increment_method_stats(Method) ->
+    CounterName = list_to_atom(string:to_lower(atom_to_list(Method)) ++ "_requests"),
+    couch_stats_collector:increment({httpd, CounterName}).
 
 special_test_authentication_handler(Req) ->
     case header_value(Req, "WWW-Authenticate") of
@@ -325,6 +338,7 @@
 
 
 start_chunked_response(#httpd{mochi_req=MochiReq}, Code, Headers) ->
+    couch_stats_collector:increment({http_status_codes, Code}),
     {ok, MochiReq:respond({Code, Headers ++ server_header(), chunked})}.
 
 send_chunk(Resp, Data) ->
@@ -332,6 +346,7 @@
     {ok, Resp}.
 
 send_response(#httpd{mochi_req=MochiReq}, Code, Headers, Body) ->
+    couch_stats_collector:increment({http_status_codes, Code}),
     if Code >= 400 ->
         ?LOG_DEBUG("HTTPd ~p error response:~n ~s", [Code, Body]);
     true -> ok

Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Sun Feb 22 13:50:38 2009
@@ -80,6 +80,7 @@
     Doc = couch_doc:from_json_obj(couch_httpd:json_body(Req)),
     DocId = couch_util:new_uuid(),
     {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=[]}, []),
+    couch_stats_collector:increment({httpd, document_creates}),
     DocUrl = absolute_uri(Req, 
         binary_to_list(<<"/",DbName/binary,"/",DocId/binary>>)),
     send_json(Req, 201, [{"Location", DocUrl}], {[
@@ -102,6 +103,7 @@
     send_method_not_allowed(Req, "POST");
 
 db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>]}=Req, Db) ->
+    couch_stats_collector:increment({httpd, bulk_requests}),
     {JsonProps} = couch_httpd:json_body(Req),
     DocsArray = proplists:get_value(<<"docs">>, JsonProps),
     case couch_httpd:header_value(Req, "X-Couch-Full-Commit", "false") of
@@ -377,6 +379,7 @@
         couch_httpd:send_error(Req, 409, <<"missing_rev">>,
             <<"Document rev/etag must be specified to delete">>);
     RevToDelete ->
+        couch_stats_collector:increment({httpd, document_deletes}),
         {ok, NewRev} = couch_db:delete_doc(Db, DocId, [RevToDelete]),
         send_json(Req, 200, {[
             {ok, true},
@@ -391,6 +394,7 @@
         open_revs = Revs,
         options = Options
     } = parse_doc_query(Req),
+    couch_stats_collector:increment({httpd, document_reads}),
     case Revs of
     [] ->
         Doc = couch_doc_open(Db, DocId, Rev, Options),
@@ -400,7 +404,7 @@
             [] -> [{"Etag", DiskEtag}]; % output etag only when we have no meta
             _ -> []
             end,
-            send_json(Req, 200, Headers, couch_doc:to_json_obj(Doc, Options))            
+            send_json(Req, 200, Headers, couch_doc:to_json_obj(Doc, Options))
         end);
     _ ->
         {ok, Results} = couch_db:open_doc_revs(Db, DocId, Revs, Options),
@@ -467,8 +471,10 @@
     end,
     case extract_header_rev(Req, ExplicitRev) of
     missing_rev ->
+        couch_stats_collector:increment({httpd, document_creates}),
         Revs = [];
     Rev ->
+        couch_stats_collector:increment({httpd, document_updates}),
         Revs = [Rev]
     end,
     {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=Revs}, Options),
@@ -492,6 +498,7 @@
 
     % save new doc
     {ok, NewTargetRev} = couch_db:update_doc(Db, Doc#doc{id=TargetDocId, revs=TargetRev}, []),
+    couch_stats_collector:increment({httpd, document_copies}),
 
     send_json(Req, 201, [{"Etag", "\"" ++ binary_to_list(NewTargetRev) ++ "\""}], {[
         {ok, true},
@@ -517,9 +524,9 @@
         Doc#doc{id=TargetDocId, revs=TargetRev},
         #doc{id=SourceDocId, revs=[SourceRev], deleted=true}
         ],
-
     {ok, ResultRevs} = couch_db:update_docs(Db, Docs, []),
-
+    couch_stats_collector:increment({httpd, document_moves}),
+    
     DocResults = lists:zipwith(
         fun(FDoc, NewRev) ->
             {[{id, FDoc#doc.id}, {rev, NewRev}]}
@@ -622,8 +629,10 @@
 
     Doc = case extract_header_rev(Req, couch_httpd:qs_value(Req, "rev")) of
         missing_rev -> % make the new doc
+            couch_stats_collector:increment({httpd, document_creates}),
             #doc{id=DocId};
         Rev ->
+            couch_stats_collector:increment({httpd, document_updates}),
             case couch_db:open_doc_revs(Db, DocId, [Rev], []) of
             {ok, [{ok, Doc0}]}  -> Doc0#doc{revs=[Rev]};
             {ok, [Error]}       -> throw(Error)

Modified: couchdb/trunk/src/couchdb/couch_httpd_misc_handlers.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_misc_handlers.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_misc_handlers.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_misc_handlers.erl Sun Feb 22 13:50:38 2009
@@ -14,7 +14,7 @@
 
 -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,
+    handle_uuids_req/1,handle_config_req/1,
     handle_task_status_req/1]).
     
 -export([increment_update_seq_req/2]).
@@ -63,13 +63,6 @@
     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_task_status_req(#httpd{method='GET'}=Req) ->
     ok = couch_httpd:verify_is_server_admin(Req),
     % convert the list of prop lists to a list of json objects

Modified: couchdb/trunk/src/couchdb/couch_httpd_view.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_view.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_view.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_view.erl Sun Feb 22 13:50:38 2009
@@ -28,8 +28,8 @@
         reduce = Reduce
     } = QueryArgs = parse_view_query(Req, Keys),
     DesignId = <<"_design/", Id/binary>>,
-    case couch_view:get_map_view(Db, DesignId, ViewName, Stale) of
-    {ok, View, Group} ->    
+    Result = case couch_view:get_map_view(Db, DesignId, ViewName, Stale) of
+    {ok, View, Group} ->
         output_map_view(Req, View, Group, Db, QueryArgs, Keys);
     {not_found, Reason} ->
         case couch_view:get_reduce_view(Db, DesignId, ViewName, Stale) of
@@ -45,7 +45,9 @@
         _ ->
             throw({not_found, Reason})
         end
-    end.
+    end,
+    couch_stats_collector:increment({httpd, view_reads}),
+    Result.
 
 handle_view_req(#httpd{method='GET',path_parts=[_,_, Id, ViewName]}=Req, Db) ->
     design_doc_view(Req, Db, Id, ViewName, nil);
@@ -60,7 +62,7 @@
 
 handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
     QueryArgs = parse_view_query(Req),
-
+    couch_stats_collector:increment({httpd, temporary_view_reads}),
     case couch_httpd:primary_header_value(Req, "content-type") of
         undefined -> ok;
         "application/json" -> ok;

Modified: couchdb/trunk/src/couchdb/couch_server.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_server.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_server.erl (original)
+++ couchdb/trunk/src/couchdb/couch_server.erl Sun Feb 22 13:50:38 2009
@@ -182,7 +182,9 @@
 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{dbs_open=NumOpen-1}};
+    ok -> 
+        couch_stats_collector:decrement({couchdb, open_databases}),   
+        {ok, Server#server{dbs_open=NumOpen - 1}};
     Error -> Error
     end.
 
@@ -235,6 +237,7 @@
                     true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}),
                     true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
                     DbsOpen = Server2#server.dbs_open + 1,
+                    couch_stats_collector:increment({couchdb, open_databases}),
                     {reply, {ok, MainPid},
                             Server2#server{dbs_open=DbsOpen}};
                 Error ->
@@ -270,6 +273,7 @@
                     true = ets:insert(couch_dbs_by_pid, {MainPid, DbName}),
                     true = ets:insert(couch_dbs_by_lru, {LruTime, DbName}),
                     DbsOpen = Server2#server.dbs_open + 1,
+                    couch_stats_collector:increment({couchdb, open_databases}),
                     couch_db_update_notifier:notify({created, DbName}),
                     {reply, {ok, MainPid},
                             Server2#server{dbs_open=DbsOpen}};
@@ -299,6 +303,7 @@
             true = ets:delete(couch_dbs_by_name, DbName),
             true = ets:delete(couch_dbs_by_pid, Pid),
             true = ets:delete(couch_dbs_by_lru, LruTime),
+            couch_stats_collector:decrement({couchdb, open_databases}),
             Server#server{dbs_open=Server#server.dbs_open - 1}
         end,
         case file:delete(FullFilepath) of
@@ -328,6 +333,7 @@
     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{dbs_open=DbsOpen-1}};
+    couch_stats_collector:decrement({couchdb, open_databases}),
+    {noreply, Server#server{dbs_open=DbsOpen - 1}};
 handle_info(Info, _Server) ->
     exit({unknown_message, Info}).

Modified: couchdb/trunk/src/couchdb/couch_server_sup.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_server_sup.erl?rev=746691&r1=746690&r2=746691&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_server_sup.erl (original)
+++ couchdb/trunk/src/couchdb/couch_server_sup.erl Sun Feb 22 13:50:38 2009
@@ -158,7 +158,6 @@
                 supervisor,
                 dynamic}]}).
 
-
 start_secondary_services() ->
     DaemonChildSpecs = [
         begin
@@ -173,7 +172,7 @@
         end
         || {Name, SpecStr}
         <- couch_config:get("daemons"), SpecStr /= ""],
-        
+    
     supervisor:start_link({local, couch_secondary_services}, couch_server_sup,
         {{one_for_one, 10, 3600}, DaemonChildSpecs}).