This is an automated email from the ASF dual-hosted git repository.
chewbranca pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/main by this push:
new ab2cf16a6 Add dbname to mango exec stats (#4990)
ab2cf16a6 is described below
commit ab2cf16a60f4cf1cdde7b3f8c2b8e9828ca46fe5
Author: Russell Branca <[email protected]>
AuthorDate: Tue Mar 5 14:44:07 2024 -0800
Add dbname to mango exec stats (#4990)
* WIP: include dbname in mango exec stats
* Don't output dbname in exec stats http response
* Make sure mango nouveau logs reports
* Test that mango reports get the dbname in the stats
* With compliant formatting
* Switch to adding exec stats dbname during create
* Add stats to explain cursor
* Add stats to mango cursor special
* Fix mango special cursor test
---
src/mango/src/mango_cursor.erl | 4 +-
src/mango/src/mango_cursor.hrl | 2 +-
src/mango/src/mango_cursor_nouveau.erl | 7 ++-
src/mango/src/mango_cursor_special.erl | 22 ++++++++--
src/mango/src/mango_cursor_text.erl | 25 +++++++----
src/mango/src/mango_cursor_view.erl | 76 ++++++++++++++++++++++++++-------
src/mango/src/mango_execution_stats.erl | 26 +++++++++--
src/mango/src/mango_execution_stats.hrl | 3 +-
8 files changed, 132 insertions(+), 33 deletions(-)
diff --git a/src/mango/src/mango_cursor.erl b/src/mango/src/mango_cursor.erl
index 3eedc7383..deb5d9144 100644
--- a/src/mango/src/mango_cursor.erl
+++ b/src/mango/src/mango_cursor.erl
@@ -424,6 +424,7 @@ create_cursor(Db, {[], Trace0}, Selector, Opts) ->
Skip = couch_util:get_value(skip, Opts, 0),
Fields = couch_util:get_value(fields, Opts, all_fields),
Bookmark = couch_util:get_value(bookmark, Opts),
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
{ok, #cursor{
db = Db,
index = none,
@@ -433,7 +434,8 @@ create_cursor(Db, {[], Trace0}, Selector, Opts) ->
limit = Limit,
skip = Skip,
fields = Fields,
- bookmark = Bookmark
+ bookmark = Bookmark,
+ execution_stats = Stats
}};
create_cursor(Db, {Indexes, Trace0}, Selector, Opts) ->
Trace1 = maps:merge(Trace0, #{filtered_indexes =>
sets:from_list(Indexes)}),
diff --git a/src/mango/src/mango_cursor.hrl b/src/mango/src/mango_cursor.hrl
index 6e5ffd6d9..cf02492a3 100644
--- a/src/mango/src/mango_cursor.hrl
+++ b/src/mango/src/mango_cursor.hrl
@@ -25,7 +25,7 @@
fields = undefined,
user_fun,
user_acc,
- execution_stats = #execution_stats{},
+ execution_stats,
bookmark,
bookmark_docid,
bookmark_key
diff --git a/src/mango/src/mango_cursor_nouveau.erl
b/src/mango/src/mango_cursor_nouveau.erl
index 5471ea46a..71beb053f 100644
--- a/src/mango/src/mango_cursor_nouveau.erl
+++ b/src/mango/src/mango_cursor_nouveau.erl
@@ -53,6 +53,8 @@ create(Db, {Indexes, Trace}, Selector, Opts) ->
Skip = couch_util:get_value(skip, Opts, 0),
Fields = couch_util:get_value(fields, Opts, all_fields),
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
+
{ok, #cursor{
db = Db,
index = Index,
@@ -62,7 +64,8 @@ create(Db, {Indexes, Trace}, Selector, Opts) ->
opts = Opts,
limit = Limit,
skip = Skip,
- fields = Fields
+ fields = Fields,
+ execution_stats = Stats
}}.
explain(Cursor) ->
@@ -128,6 +131,8 @@ execute(Cursor, UserFun, UserAcc) ->
{FinalUserAcc0, Stats1} = mango_execution_stats:maybe_add_stats(
Opts, UserFun, Stats0, FinalUserAcc
),
+ %% This needs Stats1 as log_end is called in maybe_add_stats
+ mango_execution_stats:log_stats(Stats1),
FinalUserAcc1 = mango_cursor:maybe_add_warning(UserFun, Cursor,
Stats1, FinalUserAcc0),
{ok, FinalUserAcc1}
end.
diff --git a/src/mango/src/mango_cursor_special.erl
b/src/mango/src/mango_cursor_special.erl
index 1891ba6d0..c466b5db1 100644
--- a/src/mango/src/mango_cursor_special.erl
+++ b/src/mango/src/mango_cursor_special.erl
@@ -45,6 +45,7 @@ create(Db, {Indexes, Trace0}, Selector, Opts) ->
Skip = couch_util:get_value(skip, Opts, 0),
Fields = couch_util:get_value(fields, Opts, all_fields),
Bookmark = couch_util:get_value(bookmark, Opts),
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
IndexRanges1 = mango_cursor:maybe_noop_range(Selector, IndexRanges),
Trace = maps:merge(Trace0, #{sorted_index_ranges => SortedIndexRanges}),
@@ -59,7 +60,8 @@ create(Db, {Indexes, Trace0}, Selector, Opts) ->
limit = Limit,
skip = Skip,
fields = Fields,
- bookmark = Bookmark
+ bookmark = Bookmark,
+ execution_stats = Stats
}}.
explain(Cursor) ->
@@ -74,13 +76,26 @@ handle_message(Msg, Cursor) ->
-ifdef(TEST).
-include_lib("couch/include/couch_eunit.hrl").
-create_test() ->
+create_test_() ->
+ {
+ foreach,
+ fun() ->
+ meck:expect(couch_db, name, fun(A) when is_atom(A) ->
atom_to_binary(A) end)
+ end,
+ fun(_) -> meck:unload() end,
+ [
+ ?TDEF_FE(t_create)
+ ]
+ }.
+
+t_create(_) ->
Index = #idx{type = <<"special">>, def = all_docs},
Indexes = [Index],
Ranges = [{'$gt', null, '$lt', mango_json_max}],
Trace = #{},
Selector = {[]},
Options = [{limit, limit}, {skip, skip}, {fields, fields}, {bookmark,
bookmark}],
+ Stats = mango_execution_stats:stats_init(couch_db:name(db)),
Cursor =
#cursor{
db = db,
@@ -92,7 +107,8 @@ create_test() ->
skip = skip,
fields = fields,
bookmark = bookmark,
- trace = #{sorted_index_ranges => [{Index, Ranges, 0}]}
+ trace = #{sorted_index_ranges => [{Index, Ranges, 0}]},
+ execution_stats = Stats
},
?assertEqual({ok, Cursor}, create(db, {Indexes, Trace}, Selector,
Options)).
diff --git a/src/mango/src/mango_cursor_text.erl
b/src/mango/src/mango_cursor_text.erl
index ee1d962f7..6d2204070 100644
--- a/src/mango/src/mango_cursor_text.erl
+++ b/src/mango/src/mango_cursor_text.erl
@@ -50,7 +50,9 @@ create(Db, {Indexes, Trace}, Selector, Opts0) ->
?MANGO_ERROR(multiple_text_indexes)
end,
- Opts = unpack_bookmark(couch_db:name(Db), Opts0),
+ DbName = couch_db:name(Db),
+ Opts = unpack_bookmark(DbName, Opts0),
+ Stats = mango_execution_stats:stats_init(DbName),
DreyfusLimit = get_dreyfus_limit(),
Limit = erlang:min(DreyfusLimit, couch_util:get_value(limit, Opts,
mango_opts:default_limit())),
@@ -66,7 +68,8 @@ create(Db, {Indexes, Trace}, Selector, Opts0) ->
opts = Opts,
limit = Limit,
skip = Skip,
- fields = Fields
+ fields = Fields,
+ execution_stats = Stats
}}.
explain(Cursor) ->
@@ -389,8 +392,10 @@ t_create_regular(_) ->
Limit = 10,
Options = [{limit, Limit}, {skip, skip}, {fields, fields}, {bookmark,
bookmark}],
Options1 = [{limit, Limit}, {skip, skip}, {fields, fields}, {bookmark,
unpacked_bookmark}],
+ Db = db,
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
Cursor = #cursor{
- db = db,
+ db = Db,
index = Index,
ranges = null,
trace = Trace,
@@ -398,17 +403,20 @@ t_create_regular(_) ->
opts = Options1,
limit = Limit,
skip = skip,
- fields = fields
+ fields = fields,
+ execution_stats = Stats
},
meck:expect(dreyfus_bookmark, unpack, [db_name, bookmark],
meck:val(unpacked_bookmark)),
- ?assertEqual({ok, Cursor}, create(db, {Indexes, Trace}, selector,
Options)).
+ ?assertEqual({ok, Cursor}, create(Db, {Indexes, Trace}, selector,
Options)).
t_create_no_bookmark(_) ->
Limit = 99,
Options = [{limit, Limit}, {skip, skip}, {fields, fields}, {bookmark,
nil}],
Options1 = [{limit, Limit}, {skip, skip}, {fields, fields}, {bookmark,
[]}],
+ Db = db,
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
Cursor = #cursor{
- db = db,
+ db = Db,
index = index,
ranges = null,
trace = trace,
@@ -416,9 +424,10 @@ t_create_no_bookmark(_) ->
opts = Options1,
limit = Limit,
skip = skip,
- fields = fields
+ fields = fields,
+ execution_stats = Stats
},
- ?assertEqual({ok, Cursor}, create(db, {[index], trace}, selector,
Options)).
+ ?assertEqual({ok, Cursor}, create(Db, {[index], trace}, selector,
Options)).
t_create_invalid_bookmark(_) ->
Options = [{bookmark, invalid}],
diff --git a/src/mango/src/mango_cursor_view.erl
b/src/mango/src/mango_cursor_view.erl
index b103d869d..ac8714aa7 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -105,6 +105,8 @@ create(Db, {Indexes, Trace0}, Selector, Opts) ->
IndexRanges1 = mango_cursor:maybe_noop_range(Selector, IndexRanges),
Trace = maps:merge(Trace0, #{sorted_index_ranges => SortedIndexRanges}),
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
+
{ok, #cursor{
db = Db,
index = Index,
@@ -115,7 +117,8 @@ create(Db, {Indexes, Trace0}, Selector, Opts) ->
limit = Limit,
skip = Skip,
fields = Fields,
- bookmark = Bookmark
+ bookmark = Bookmark,
+ execution_stats = Stats
}}.
-spec required_fields(#cursor{}) -> fields().
@@ -906,16 +909,30 @@ composite_indexes_test() ->
],
?assertEqual(Result, composite_indexes(Indexes, Ranges)).
-create_test() ->
+create_test_() ->
+ {
+ foreach,
+ fun() ->
+ meck:expect(couch_db, name, fun(A) when is_atom(A) ->
atom_to_binary(A) end)
+ end,
+ fun(_) -> meck:unload() end,
+ [
+ ?TDEF_FE(t_create_ok)
+ ]
+ }.
+
+t_create_ok(_) ->
Index = #idx{type = <<"json">>, def = {[{<<"fields">>, {[]}}]}},
Indexes = [Index],
Trace = #{},
Ranges = [],
Selector = {[]},
Options = [{limit, limit}, {skip, skip}, {fields, fields}, {bookmark,
bookmark}],
+ Db = db,
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
Cursor =
#cursor{
- db = db,
+ db = Db,
index = Index,
ranges = Ranges,
selector = Selector,
@@ -924,9 +941,10 @@ create_test() ->
skip = skip,
fields = fields,
bookmark = bookmark,
- trace = #{sorted_index_ranges => [{Index, [], 0}]}
+ trace = #{sorted_index_ranges => [{Index, [], 0}]},
+ execution_stats = Stats
},
- ?assertEqual({ok, Cursor}, create(db, {Indexes, Trace}, Selector,
Options)).
+ ?assertEqual({ok, Cursor}, create(Db, {Indexes, Trace}, Selector,
Options)).
to_selector(Map) ->
test_util:as_selector(Map).
@@ -993,7 +1011,8 @@ execute_test_() ->
fun() ->
meck:new(foo, [non_strict]),
meck:new(fabric),
- meck:new(chttpd_stats)
+ meck:new(chttpd_stats),
+ meck:expect(couch_db, name, fun(A) when is_atom(A) ->
atom_to_binary(A) end)
end,
fun(_) -> meck:unload() end,
[
@@ -1007,7 +1026,9 @@ execute_test_() ->
}.
t_execute_empty(_) ->
- Cursor = #cursor{ranges = [empty]},
+ Db = db,
+ Stats = mango_execution_stats:stats_init(couch_db:name(Db)),
+ Cursor = #cursor{ranges = [empty], execution_stats = Stats},
meck:expect(fabric, all_docs, ['_', '_', '_', '_', '_'], meck:val(error)),
meck:expect(fabric, query_view, ['_', '_', '_', '_', '_', '_'],
meck:val(error)),
?assertEqual({ok, accumulator}, execute(Cursor, undefined, accumulator)),
@@ -1023,6 +1044,7 @@ t_execute_ok_all_docs(_) ->
Index = #idx{type = <<"json">>, def = all_docs},
Selector = {[]},
Fields = all_fields,
+ Stats = mango_execution_stats:stats_init(db),
Cursor =
#cursor{
index = Index,
@@ -1031,7 +1053,8 @@ t_execute_ok_all_docs(_) ->
fields = Fields,
ranges = [{'$gte', start_key, '$lte', end_key}],
opts = [{user_ctx, user_ctx}],
- bookmark = nil
+ bookmark = nil,
+ execution_stats = Stats
},
Cursor1 =
Cursor#cursor{
@@ -1050,7 +1073,8 @@ t_execute_ok_all_docs(_) ->
#execution_stats{
totalKeysExamined = TotalKeysExamined,
totalDocsExamined = TotalDocsExamined,
- executionStartTime = {0, 0, 0}
+ executionStartTime = {0, 0, 0},
+ dbname = db
}
},
Extra =
@@ -1089,6 +1113,7 @@ t_execute_ok_query_view(_) ->
IndexScanWarning =
<<"The number of documents examined is high in proportion to the
number of results returned. Consider adding a more specific index to improve
this.">>,
UserFnParameters2 = [{add_key, warning, IndexScanWarning}, accumulator2],
+ Stats = mango_execution_stats:stats_init(db),
meck:expect(
foo,
bar,
@@ -1114,7 +1139,8 @@ t_execute_ok_query_view(_) ->
fields = Fields,
ranges = [{'$gte', start_key, '$lte', end_key}],
opts = [{user_ctx, user_ctx}],
- bookmark = nil
+ bookmark = nil,
+ execution_stats = Stats
},
Cursor1 =
Cursor#cursor{
@@ -1131,6 +1157,7 @@ t_execute_ok_query_view(_) ->
bookmark_key = undefined,
execution_stats =
#execution_stats{
+ dbname = db,
totalKeysExamined = TotalKeysExamined,
totalDocsExamined = TotalDocsExamined,
executionStartTime = {0, 0, 0}
@@ -1174,18 +1201,22 @@ t_execute_ok_query_view(_) ->
t_execute_ok_all_docs_with_execution_stats(_) ->
Bookmark = bookmark,
+ DbName = db,
TotalKeysExamined = 33,
TotalDocsExamined = 12,
TotalQuorumDocsExamined = 0,
ResultsReturned = 20,
+ InitStats = mango_execution_stats:stats_init(couch_db:name(DbName)),
ExecutionStats =
#execution_stats{
totalKeysExamined = TotalKeysExamined,
totalDocsExamined = TotalDocsExamined,
totalQuorumDocsExamined = TotalQuorumDocsExamined,
resultsReturned = ResultsReturned,
- executionStartTime = {0, 0, 0}
+ executionStartTime = {0, 0, 0},
+ dbname = DbName
},
+ %% Stats doesn't include dbname as it will have already been stripped out
Stats =
{[
{total_keys_examined, TotalKeysExamined},
@@ -1209,12 +1240,13 @@ t_execute_ok_all_docs_with_execution_stats(_) ->
Cursor =
#cursor{
index = Index,
- db = db,
+ db = DbName,
selector = Selector,
fields = Fields,
ranges = [{'$gte', start_key, '$lte', end_key}],
opts = [{user_ctx, user_ctx}, {execution_stats, true}],
- bookmark = nil
+ bookmark = nil,
+ execution_stats = InitStats
},
Cursor1 =
Cursor#cursor{
@@ -1253,13 +1285,24 @@ t_execute_ok_all_docs_with_execution_stats(_) ->
Parameters = [
db, [{user_ctx, user_ctx}], fun
mango_cursor_view:handle_all_docs_message/2, Cursor1, Args
],
+ meck:new(couch_log, [passthrough]),
+ %% Pattern matching on DbName in the fun head results in a shadowed
variable
+ %% warning. Creating a new variable and testing in the guard works around
this.
+ meck:expect(
+ couch_log,
+ report,
+ fun("mango-stats", #{dbname := DbName1}) when DbName1 =:= DbName ->
true end
+ ),
+ meck:expect(chttpd_stats, incr_rows, [TotalKeysExamined], meck:val(ok)),
meck:expect(chttpd_stats, incr_rows, [TotalKeysExamined], meck:val(ok)),
meck:expect(chttpd_stats, incr_reads, [TotalDocsExamined], meck:val(ok)),
meck:expect(fabric, all_docs, Parameters, meck:val({ok, Cursor2})),
?assertEqual({ok, updated_accumulator2}, execute(Cursor, fun foo:bar/2,
accumulator)),
+ ?assert(meck:called(couch_log, report, '_')),
?assert(meck:called(fabric, all_docs, '_')).
t_execute_error_1(_) ->
+ Stats = mango_execution_stats:stats_init(db),
Cursor =
#cursor{
index = #idx{type = <<"json">>, ddoc = <<"_design/ghibli">>, name
= index_name},
@@ -1268,7 +1311,8 @@ t_execute_error_1(_) ->
fields = all_fields,
ranges = [{'$gte', start_key, '$lte', end_key}],
opts = [{user_ctx, user_ctx}],
- bookmark = nil
+ bookmark = nil,
+ execution_stats = Stats
},
Parameters = [
db, '_', <<"ghibli">>, index_name, fun
mango_cursor_view:handle_message/2, '_', '_'
@@ -1279,6 +1323,7 @@ t_execute_error_1(_) ->
?assertNot(meck:called(chttpd_stats, incr_reads, '_')).
t_execute_error_2(_) ->
+ Stats = mango_execution_stats:stats_init(db),
Cursor =
#cursor{
index = #idx{type = <<"json">>, ddoc = <<"_design/ghibli">>, name
= index_name},
@@ -1287,7 +1332,8 @@ t_execute_error_2(_) ->
fields = all_fields,
ranges = [{'$gte', start_key, '$lte', end_key}],
opts = [{user_ctx, user_ctx}],
- bookmark = nil
+ bookmark = nil,
+ execution_stats = Stats
},
Parameters = [
db, '_', <<"ghibli">>, index_name, fun
mango_cursor_view:handle_message/2, '_', '_'
diff --git a/src/mango/src/mango_execution_stats.erl
b/src/mango/src/mango_execution_stats.erl
index dce7c087b..67a1edd0a 100644
--- a/src/mango/src/mango_execution_stats.erl
+++ b/src/mango/src/mango_execution_stats.erl
@@ -13,7 +13,7 @@
-module(mango_execution_stats).
-export([
- to_json/1,
+ to_json/1, to_json/2,
to_map/1,
incr_keys_examined/1,
incr_keys_examined/2,
@@ -28,7 +28,8 @@
shard_init/0,
shard_incr_keys_examined/0,
shard_incr_docs_examined/0,
- shard_get_stats/0
+ shard_get_stats/0,
+ stats_init/0, stats_init/1
]).
-include("mango.hrl").
@@ -36,13 +37,31 @@
-define(SHARD_STATS_KEY, mango_shard_execution_stats).
+stats_init() ->
+ #execution_stats{}.
+
+stats_init(DbName) ->
+ Stats = stats_init(),
+ Stats#execution_stats{dbname = DbName}.
+
to_json(Stats) ->
+ to_json(Stats, true).
+
+to_json(Stats, IncludeDbName) ->
+ Base =
+ case IncludeDbName of
+ true ->
+ [{dbname, Stats#execution_stats.dbname}];
+ false ->
+ []
+ end,
{[
{total_keys_examined, Stats#execution_stats.totalKeysExamined},
{total_docs_examined, Stats#execution_stats.totalDocsExamined},
{total_quorum_docs_examined,
Stats#execution_stats.totalQuorumDocsExamined},
{results_returned, Stats#execution_stats.resultsReturned},
{execution_time_ms, Stats#execution_stats.executionTimeMs}
+ | Base
]}.
to_map(Stats) ->
@@ -51,6 +70,7 @@ to_map(Stats) ->
total_docs_examined => Stats#execution_stats.totalDocsExamined,
total_quorum_docs_examined =>
Stats#execution_stats.totalQuorumDocsExamined,
results_returned => Stats#execution_stats.resultsReturned,
+ dbname => Stats#execution_stats.dbname,
execution_time_ms => Stats#execution_stats.executionTimeMs
}.
@@ -103,7 +123,7 @@ maybe_add_stats(Opts, UserFun, Stats0, UserAcc) ->
FinalAcc =
case couch_util:get_value(execution_stats, Opts) of
true ->
- JSONValue = to_json(Stats1),
+ JSONValue = to_json(Stats1, false),
Arg = {add_key, execution_stats, JSONValue},
{_Go, FinalUserAcc} = UserFun(Arg, UserAcc),
FinalUserAcc;
diff --git a/src/mango/src/mango_execution_stats.hrl
b/src/mango/src/mango_execution_stats.hrl
index ea5ed5ee8..302460c26 100644
--- a/src/mango/src/mango_execution_stats.hrl
+++ b/src/mango/src/mango_execution_stats.hrl
@@ -16,5 +16,6 @@
totalQuorumDocsExamined = 0,
resultsReturned = 0,
executionStartTime,
- executionTimeMs
+ executionTimeMs,
+ dbname
}).