Skip to content

Commit

Permalink
PoC couch_stats local resource usage tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
chewbranca committed Oct 11, 2023
1 parent ede7ff2 commit be84279
Show file tree
Hide file tree
Showing 18 changed files with 745 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/chttpd/src/chttpd_httpd_handlers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ url_handler(<<"_utils">>) -> fun chttpd_misc:handle_utils_dir_req/1;
url_handler(<<"_all_dbs">>) -> fun chttpd_misc:handle_all_dbs_req/1;
url_handler(<<"_dbs_info">>) -> fun chttpd_misc:handle_dbs_info_req/1;
url_handler(<<"_active_tasks">>) -> fun chttpd_misc:handle_task_status_req/1;
url_handler(<<"_active_resources">>) -> fun chttpd_misc:handle_resource_status_req/1;
url_handler(<<"_scheduler">>) -> fun couch_replicator_httpd:handle_scheduler_req/1;
url_handler(<<"_node">>) -> fun chttpd_node:handle_node_req/1;
url_handler(<<"_reload_query_servers">>) -> fun chttpd_misc:handle_reload_query_servers_req/1;
Expand Down
15 changes: 15 additions & 0 deletions src/chttpd/src/chttpd_misc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
handle_replicate_req/1,
handle_reload_query_servers_req/1,
handle_task_status_req/1,
handle_resource_status_req/1,
handle_up_req/1,
handle_utils_dir_req/1,
handle_utils_dir_req/2,
Expand Down Expand Up @@ -230,6 +231,20 @@ handle_task_status_req(#httpd{method = 'GET'} = Req) ->
handle_task_status_req(Req) ->
send_method_not_allowed(Req, "GET,HEAD").

handle_resource_status_req(#httpd{method = 'GET'} = Req) ->
ok = chttpd:verify_is_server_admin(Req),
{Resp, Bad} = rpc:multicall(erlang, apply, [
fun() ->
{node(), couch_stats_resource_tracker:active()}
end,
[]
]),
%% TODO: incorporate Bad responses
io:format("ACTIVE RESP: ~p~nBAD RESP: ~p~n", [Resp, Bad]),
send_json(Req, {Resp});
handle_resource_status_req(Req) ->
send_method_not_allowed(Req, "GET,HEAD").

handle_replicate_req(#httpd{method = 'POST', user_ctx = Ctx, req_body = PostBody} = Req) ->
chttpd:validate_ctype(Req, "application/json"),
%% see HACK in chttpd.erl about replication
Expand Down
5 changes: 5 additions & 0 deletions src/couch/priv/stats_descriptions.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@
{type, counter},
{desc, <<"number of legacy checksums found in couch_file instances">>}
]}.
%% CSRT (couch_stats_resource_tracker) stats
{[couchdb, csrt, delta_missing_t0], [
{type, counter},
{desc, <<"number of csrt contexts without a proper startime">>}
]}.
{[pread, exceed_eof], [
{type, counter},
{desc, <<"number of the attempts to read beyond end of db file">>}
Expand Down
3 changes: 3 additions & 0 deletions src/couch/src/couch_btree.erl
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,8 @@ reduce_tree_size(kp_node, NodeSize, [{_K, {_P, _Red, Sz}} | NodeList]) ->

get_node(#btree{fd = Fd}, NodePos) ->
{ok, {NodeType, NodeList}} = couch_file:pread_term(Fd, NodePos),
%% TODO: wire in csrt tracking
couch_stats:increment_counter([couchdb, btree, get_node]),
{NodeType, NodeList}.

write_node(#btree{fd = Fd, compression = Comp} = Bt, NodeType, NodeList) ->
Expand Down Expand Up @@ -1163,6 +1165,7 @@ stream_kv_node2(Bt, Reds, PrevKVs, [{K, V} | RestKVs], InRange, Dir, Fun, Acc) -
false ->
{stop, {PrevKVs, Reds}, Acc};
true ->
couch_stats:increment_counter([couchdb, btree, changes_processed]),
AssembledKV = assemble(Bt, K, V),
case Fun(visit, AssembledKV, {PrevKVs, Reds}, Acc) of
{ok, Acc2} ->
Expand Down
2 changes: 2 additions & 0 deletions src/couch/src/couch_db.erl
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ open_doc(Db, IdOrDocInfo) ->
open_doc(Db, IdOrDocInfo, []).

open_doc(Db, Id, Options) ->
%% TODO: wire in csrt tracking
increment_stat(Db, [couchdb, database_reads]),
case open_doc_int(Db, Id, Options) of
{ok, #doc{deleted = true} = Doc} ->
Expand Down Expand Up @@ -1982,6 +1983,7 @@ increment_stat(#db{options = Options}, Stat, Count) when
->
case lists:member(sys_db, Options) of
true ->
%% TODO: we shouldn't leak resource usage just because it's a sys_db
ok;
false ->
couch_stats:increment_counter(Stat, Count)
Expand Down
8 changes: 8 additions & 0 deletions src/couch/src/couch_query_servers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ filter_docs(Req, Db, DDoc, FName, Docs) ->
{ok, filter_docs_int(Db, DDoc, FName, JsonReq, JsonDocs)}
catch
throw:{os_process_error, {exit_status, 1}} ->
%% TODO: wire in csrt tracking
couch_stats:increment_counter([couchdb, query_server, js_filter_error]),
%% batch used too much memory, retry sequentially.
Fun = fun(JsonDoc) ->
filter_docs_int(Db, DDoc, FName, JsonReq, [JsonDoc])
Expand All @@ -550,6 +552,12 @@ filter_docs(Req, Db, DDoc, FName, Docs) ->
end.

filter_docs_int(Db, DDoc, FName, JsonReq, JsonDocs) ->
%% Count usage in _int version as this can be repeated for OS error
%% Pros & cons... might not have actually processed `length(JsonDocs)` docs
%% but it certainly undercounts if we count in `filter_docs/5` above
%% TODO: wire in csrt tracking
couch_stats:increment_counter([couchdb, query_server, js_filter]),
couch_stats:increment_counter([couchdb, query_server, js_filtered_docs], length(JsonDocs)),
[true, Passes] = ddoc_prompt(
Db,
DDoc,
Expand Down
2 changes: 2 additions & 0 deletions src/couch/src/couch_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ sup_start_link(N) ->
gen_server:start_link({local, couch_server(N)}, couch_server, [N], []).

open(DbName, Options) ->
%% TODO: wire in csrt tracking
couch_stats:increment_counter([couchdb, couch_server, open]),
try
validate_open_or_create(DbName, Options),
open_int(DbName, Options)
Expand Down
30 changes: 30 additions & 0 deletions src/couch_stats/src/couch_stats.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
update_gauge/2
]).

%% couch_stats_resource_tracker API
-export([
create_context/3,
maybe_track_rexi_init_p/1
]).

-type response() :: ok | {error, unknown_metric} | {error, invalid_metric}.
-type stat() :: {any(), [{atom(), any()}]}.

Expand All @@ -49,6 +55,11 @@ increment_counter(Name) ->

-spec increment_counter(any(), pos_integer()) -> response().
increment_counter(Name, Value) ->
%% Should maybe_track_local happen before or after notify?
%% If after, only currently tracked metrics declared in the app's
%% stats_description.cfg will be trackable locally. Pros/cons.
%io:format("NOTIFY_EXISTING_METRIC: ~p || ~p || ~p~n", [Name, Op, Type]),
ok = maybe_track_local_counter(Name, Value),
case couch_stats_util:get_counter(Name, stats()) of
{ok, Ctx} -> couch_stats_counter:increment(Ctx, Value);
{error, Error} -> {error, Error}
Expand Down Expand Up @@ -100,6 +111,25 @@ stats() ->
now_sec() ->
erlang:monotonic_time(second).

%% Only potentially track positive increments to counters
-spec maybe_track_local_counter(any(), any()) -> ok.
maybe_track_local_counter(Name, Val) when is_integer(Val) andalso Val > 0 ->
%%io:format("maybe_track_local[~p]: ~p~n", [Val, Name]),
couch_stats_resource_tracker:maybe_inc(Name, Val),
ok;
maybe_track_local_counter(_, _) ->
ok.

create_context(From, MFA, Nonce) ->
couch_stats_resource_tracker:create_context(From, MFA, Nonce).

maybe_track_rexi_init_p({M, F, _A}) ->
Metric = [M, F, spawned],
case couch_stats_resource_tracker:should_track(Metric) of
true -> increment_counter(Metric);
false -> ok
end.

-ifdef(TEST).

-include_lib("couch/include/couch_eunit.hrl").
Expand Down
Loading

0 comments on commit be84279

Please sign in to comment.