This is an automated email from the ASF dual-hosted git repository.

iilyak pushed a commit to branch couch-stats-resource-tracker-v3-rebase-http-2
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 9264f5af8629c6e082fe3264765bc78866406c8d
Author: ILYA Khlopotov <iil...@apache.org>
AuthorDate: Wed Jun 25 07:14:27 2025 -0700

    Factor out csrt_entry.erl
---
 src/couch_stats/src/csrt_entry.erl               | 60 ++++++++++++++++++++++++
 src/couch_stats/src/csrt_httpd.erl               | 23 +--------
 src/couch_stats/src/csrt_query.erl               | 28 +----------
 src/couch_stats/src/csrt_util.erl                | 41 +---------------
 src/couch_stats/test/eunit/csrt_logger_tests.erl | 14 +++---
 src/couch_stats/test/eunit/csrt_server_tests.erl |  4 +-
 6 files changed, 75 insertions(+), 95 deletions(-)

diff --git a/src/couch_stats/src/csrt_entry.erl 
b/src/couch_stats/src/csrt_entry.erl
new file mode 100644
index 000000000..3b1cf3f50
--- /dev/null
+++ b/src/couch_stats/src/csrt_entry.erl
@@ -0,0 +1,60 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(csrt_entry).
+
+-include_lib("stdlib/include/ms_transform.hrl").
+-include_lib("couch_stats_resource_tracker.hrl").
+
+-export([
+    value/2,
+    key/1
+]).
+
+-spec value(#rctx{}, rctx_field()) -> any().
+
+value(#rctx{pid_ref = Val}, pid_ref) -> Val;
+value(#rctx{nonce = Val}, nonce) -> Val;
+value(#rctx{type = Val}, type) -> csrt_util:convert_type(Val);
+value(#rctx{dbname = Val}, dbname) -> Val;
+value(#rctx{username = Val}, username) -> Val;
+value(#rctx{db_open = Val}, db_open) -> Val;
+value(#rctx{docs_read = Val}, docs_read) -> Val;
+value(#rctx{docs_written = Val}, docs_written) -> Val;
+value(#rctx{rows_read = Val}, rows_read) -> Val;
+value(#rctx{changes_returned = Val}, changes_returned) -> Val;
+value(#rctx{ioq_calls = Val}, ioq_calls) -> Val;
+value(#rctx{js_filter = Val}, js_filter) -> Val;
+value(#rctx{js_filtered_docs = Val}, js_filtered_docs) -> Val;
+value(#rctx{get_kv_node = Val}, get_kv_node) -> Val;
+value(#rctx{get_kp_node = Val}, get_kp_node) -> Val;
+value(#rctx{started_at = Val}, started_at) -> Val;
+value(#rctx{updated_at = Val}, updated_at) -> Val.
+
+-spec key(BinKey :: binary() | string()) -> Key :: rctx_field()
+    | throw({bad_request, Reason :: binary()}).
+
+key(<<"pid_ref">>) -> pid_ref;
+key(<<"nonce">>) -> nonce;
+key(<<"type">>) -> type;
+key(<<"dbname">>) -> dbname;
+key(<<"username">>) -> username;
+key(<<"db_open">>) -> db_open;
+key(<<"docs_read">>) -> docs_read;
+key(<<"rows_read">>) -> rows_read;
+key(<<"changes_returned">>) -> changes_returned;
+key(<<"ioq_calls">>) -> ioq_calls;
+key(<<"js_filter">>) -> js_filter;
+key(<<"js_filtered_docs">>) -> js_filtered_docs;
+key(<<"get_kv_node">>) -> get_kv_node;
+key(<<"get_kp_node">>) -> get_kp_node;
+key(Other) when is_binary(Other) -> throw({bad_request, <<"Invalid key '", 
Other/binary, "'">>}).
diff --git a/src/couch_stats/src/csrt_httpd.erl 
b/src/couch_stats/src/csrt_httpd.erl
index e4eb13fd2..5c260d596 100644
--- a/src/couch_stats/src/csrt_httpd.erl
+++ b/src/couch_stats/src/csrt_httpd.erl
@@ -129,37 +129,18 @@ query_matcher(MatcherName, AggregationKey, CounterKey) ->
             csrt_query:query_matcher(Matcher, AggregationKey, CounterKey)
     end.
 
--spec to_key(BinKey :: binary() | string()) -> Key :: rctx_field()
-    | throw({bad_request, Reason :: binary()}).
-
-to_key(<<"pid_ref">>) -> pid_ref;
-to_key(<<"nonce">>) -> nonce;
-to_key(<<"type">>) -> type;
-to_key(<<"dbname">>) -> dbname;
-to_key(<<"username">>) -> username;
-to_key(<<"db_open">>) -> db_open;
-to_key(<<"docs_read">>) -> docs_read;
-to_key(<<"rows_read">>) -> rows_read;
-to_key(<<"changes_returned">>) -> changes_returned;
-to_key(<<"ioq_calls">>) -> ioq_calls;
-to_key(<<"js_filter">>) -> js_filter;
-to_key(<<"js_filtered_docs">>) -> js_filtered_docs;
-to_key(<<"get_kv_node">>) -> get_kv_node;
-to_key(<<"get_kp_node">>) -> get_kp_node;
-to_key(Other) when is_binary(Other) -> throw({bad_request, <<"Invalid key '", 
Other/binary, "'">>}).
-
 -spec parse_key(Keys :: binary() | [binary()]) -> [rctx_field()]
     | throw({bad_request, Reason :: binary()}).
 
 parse_key(Keys) when is_list(Keys) ->
     parse_key(Keys, []);
 parse_key(BinKey) when is_binary(BinKey) ->
-    to_key(BinKey);
+    csrt_entry:key(BinKey);
 parse_key(undefined) ->
     undefined.
 
 parse_key([BinKey | Rest], Keys) ->
-    parse_key(Rest, [to_key(BinKey) | Keys]);
+    parse_key(Rest, [csrt_entry:key(BinKey) | Keys]);
 parse_key([], Keys) ->
     lists:reverse(Keys).
 
diff --git a/src/couch_stats/src/csrt_query.erl 
b/src/couch_stats/src/csrt_query.erl
index 97a0be751..a512366a9 100644
--- a/src/couch_stats/src/csrt_query.erl
+++ b/src/couch_stats/src/csrt_query.erl
@@ -92,32 +92,8 @@ find_by_pidref(PidRef) ->
 find_workers_by_pidref(PidRef) ->
     csrt_server:match_resource(#rctx{type = #rpc_worker{from = PidRef}}).
 
-field(#rctx{pid_ref = Val}, pid_ref) -> Val;
-%% NOTE: Pros and cons to doing these convert functions here
-%% Ideally, this would be done later so as to prefer the core data structures
-%% as long as possible, but we currently need the output of this function to
-%% be jiffy:encode'able. The tricky bit is dynamically encoding the group_by
-%% structure provided by the caller of *_by aggregator functions below.
-%% For now, we just always return jiffy:encode'able data types.
-field(#rctx{nonce = Val}, nonce) -> Val;
-field(#rctx{type = Val}, type) -> csrt_util:convert_type(Val);
-field(#rctx{dbname = Val}, dbname) -> Val;
-field(#rctx{username = Val}, username) -> Val;
-field(#rctx{db_open = Val}, db_open) -> Val;
-field(#rctx{docs_read = Val}, docs_read) -> Val;
-field(#rctx{docs_written = Val}, docs_written) -> Val;
-field(#rctx{rows_read = Val}, rows_read) -> Val;
-field(#rctx{changes_returned = Val}, changes_returned) -> Val;
-field(#rctx{ioq_calls = Val}, ioq_calls) -> Val;
-field(#rctx{js_filter = Val}, js_filter) -> Val;
-field(#rctx{js_filtered_docs = Val}, js_filtered_docs) -> Val;
-field(#rctx{get_kv_node = Val}, get_kv_node) -> Val;
-field(#rctx{get_kp_node = Val}, get_kp_node) -> Val;
-field(#rctx{started_at = Val}, started_at) -> Val;
-field(#rctx{updated_at = Val}, updated_at) -> Val.
-
 curry_field(Field) ->
-    fun(Ele) -> field(Ele, Field) end.
+    fun(Ele) -> csrt_entry:value(Ele, Field) end.
 
 count_by(KeyFun) ->
     csrt_query:count_by(all(), KeyFun).
@@ -167,7 +143,7 @@ all() ->
 %% eg: group_by(all(), [username, dbname, mfa], ioq_calls).
 %% eg: group_by(all(), [username, dbname, mfa], js_filters).
 group_by(Matcher, KeyL, ValFun, AggFun, Limit) when is_list(KeyL) ->
-    KeyFun = fun(Ele) -> list_to_tuple([field(Ele, Key) || Key <- KeyL]) end,
+    KeyFun = fun(Ele) -> list_to_tuple([csrt_entry:value(Ele, Key) || Key <- 
KeyL]) end,
     group_by(Matcher, KeyFun, ValFun, AggFun, Limit);
 group_by(Matcher, Key, ValFun, AggFun, Limit) when is_atom(Key) ->
     group_by(Matcher, curry_field(Key), ValFun, AggFun, Limit);
diff --git a/src/couch_stats/src/csrt_util.erl 
b/src/couch_stats/src/csrt_util.erl
index c19c10d6f..4da5dc610 100644
--- a/src/couch_stats/src/csrt_util.erl
+++ b/src/couch_stats/src/csrt_util.erl
@@ -58,7 +58,6 @@
     set_fabric_init_p/2,
     set_fabric_init_p/3,
     map_to_rctx/1,
-    field/2,
     rctx_record_info/0
 ]).
 
@@ -276,42 +275,6 @@ map_to_rctx_field(_, _, Rctx) ->
     %% Unknown key, could throw but just move on
     Rctx.
 
--spec field(Field :: rctx_field(), Rctx :: rctx()) -> any().
-field(updated_at, #rctx{updated_at = Val}) ->
-    Val;
-field(started_at, #rctx{started_at = Val}) ->
-    Val;
-field(pid_ref, #rctx{pid_ref = Val}) ->
-    Val;
-field(nonce, #rctx{nonce = Val}) ->
-    Val;
-field(dbname, #rctx{dbname = Val}) ->
-    Val;
-field(username, #rctx{username = Val}) ->
-    Val;
-field(db_open, #rctx{db_open = Val}) ->
-    Val;
-field(docs_read, #rctx{docs_read = Val}) ->
-    Val;
-field(docs_written, #rctx{docs_written = Val}) ->
-    Val;
-field(js_filter, #rctx{js_filter = Val}) ->
-    Val;
-field(js_filtered_docs, #rctx{js_filtered_docs = Val}) ->
-    Val;
-field(rows_read, #rctx{rows_read = Val}) ->
-    Val;
-field(type, #rctx{type = Val}) ->
-    Val;
-field(get_kp_node, #rctx{get_kp_node = Val}) ->
-    Val;
-field(get_kv_node, #rctx{get_kv_node = Val}) ->
-    Val;
-field(changes_returned, #rctx{changes_returned = Val}) ->
-    Val;
-field(ioq_calls, #rctx{ioq_calls = Val}) ->
-    Val.
-
 -spec add_delta(T :: term(), Delta :: maybe_delta()) -> term_delta().
 add_delta(T, undefined) ->
     T;
@@ -520,10 +483,10 @@ t_should_not_track_init_p(_) ->
 t_should_extract_fields_properly(_) ->
     Rctx = #rctx{},
     #{fields := Fields} = rctx_record_info(),
-    %% field/2 throws on invalid fields, assert that the function succeeded
+    %% csrt_entry:value/2 throws on invalid fields, assert that the function 
succeeded
     TestField = fun(Field) ->
         try
-            field(Field, Rctx),
+            csrt_entry:value(Rctx, Field),
             true
         catch
             _:_ -> false
diff --git a/src/couch_stats/test/eunit/csrt_logger_tests.erl 
b/src/couch_stats/test/eunit/csrt_logger_tests.erl
index 8d781de76..74c88590b 100644
--- a/src/couch_stats/test/eunit/csrt_logger_tests.erl
+++ b/src/couch_stats/test/eunit/csrt_logger_tests.erl
@@ -288,8 +288,8 @@ t_matcher_on_changes_processed(#{rctxs := Rctxs0}) ->
     %% Make sure we have at least one match
     Rctxs = [rctx_gen(#{rows_read => Threshold + 10}) | Rctxs0],
     ChangesFilter = fun(R) ->
-        Ret = csrt_util:field(changes_returned, R),
-        Proc = csrt_util:field(rows_read, R),
+        Ret = csrt_entry:value(R, changes_returned),
+        Proc = csrt_entry:value(R, rows_read),
         (Proc - Ret) >= Threshold
     end,
     ?assertEqual(
@@ -309,8 +309,8 @@ t_matcher_on_long_reqs(#{rctxs := Rctxs0}) ->
     UpdatedAt = Now - round(NativeThreshold * 1.23),
     Rctxs = [rctx_gen(#{started_at => Now, updated_at => UpdatedAt}) | Rctxs0],
     DurationFilter = fun(R) ->
-        Started = csrt_util:field(started_at, R),
-        Updated = csrt_util:field(updated_at, R),
+        Started = csrt_entry:value(R, started_at),
+        Updated = csrt_entry:value(R, updated_at),
         abs(Updated - Started) >= NativeThreshold
     end,
     ?assertEqual(
@@ -472,7 +472,7 @@ matcher_on(Field, Value) ->
     matcher_for(Field, Value, fun erlang:'=:='/2).
 
 matcher_for(Field, Value, Op) ->
-    fun(Rctx) -> Op(csrt_util:field(Field, Rctx), Value) end.
+    fun(Rctx) -> Op(csrt_entry:value(Rctx, Field), Value) end.
 
 matcher_for_csrt(MatcherName) ->
     Matchers = #{MatcherName => {_, _} = csrt_logger:get_matcher(MatcherName)},
@@ -487,9 +487,9 @@ matcher_for_csrt(MatcherName) ->
 matcher_for_dbname_io(Dbname0, Threshold) ->
     Dbname = list_to_binary(Dbname0),
     fun(Rctx) ->
-        DbnameA = csrt_util:field(dbname, Rctx),
+        DbnameA = csrt_entry:value(Rctx, dbname),
         Fields = [ioq_calls, get_kv_node, get_kp_node, docs_read, rows_read],
-        Vals = [{F, csrt_util:field(F, Rctx)} || F <- Fields],
+        Vals = [{F, csrt_entry:value(Rctx, F)} || F <- Fields],
         Dbname =:= mem3:dbname(DbnameA) andalso lists:any(fun({_K, V}) -> V >= 
Threshold end, Vals)
     end.
 
diff --git a/src/couch_stats/test/eunit/csrt_server_tests.erl 
b/src/couch_stats/test/eunit/csrt_server_tests.erl
index 04203b6aa..732c4fa3f 100644
--- a/src/couch_stats/test/eunit/csrt_server_tests.erl
+++ b/src/couch_stats/test/eunit/csrt_server_tests.erl
@@ -278,8 +278,8 @@ t_updated_at({_Ctx, DbName, _View}) ->
         docs_written => 0,
         pid_ref => PidRef
     }),
-    Started = csrt_util:field(started_at, RawRctx),
-    Updated = csrt_util:field(updated_at, RawRctx),
+    Started = csrt_entry:value(RawRctx, started_at),
+    Updated = csrt_entry:value(RawRctx, updated_at),
     ?assert(
         csrt_util:make_dt(Started, Updated, millisecond) > TimeDelay,
         "updated_at gets updated with an expected TimeDelay"

Reply via email to