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

pgj 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 4f3dc9526 mango: communicate rows read for global stats collection
4f3dc9526 is described below

commit 4f3dc9526329bbb5bc6f15d5683da856b195a674
Author: Gabor Pali <[email protected]>
AuthorDate: Sat Dec 16 15:07:26 2023 +0100

    mango: communicate rows read for global stats collection
    
    Besides the execution statistics that could be shown for the user,
    the number of rows and documents read are tracked separately on
    the global level.  (Which is more like a bug than a feature, but
    that is out of the scope of this change.)
    
    With the introduction of covering indexes, these two have been
    become different, therefore global counting has to be taught about
    the number of times when no documents were read but rows only.  For
    text indexes, the number of rows and documents should be the same,
    the distinction makes sense only for json indexes.
---
 src/mango/src/mango_cursor_text.erl       | 223 +++++++++++++++++-------------
 src/mango/src/mango_cursor_view.erl       |  84 ++++++++---
 src/mango/src/mango_execution_stats.erl   |   6 +-
 src/mango/test/15-execution-stats-test.py |   2 +-
 4 files changed, 198 insertions(+), 117 deletions(-)

diff --git a/src/mango/src/mango_cursor_text.erl 
b/src/mango/src/mango_cursor_text.erl
index 5f13499b9..ee1d962f7 100644
--- a/src/mango/src/mango_cursor_text.erl
+++ b/src/mango/src/mango_cursor_text.erl
@@ -181,13 +181,14 @@ handle_hit(CAcc0, Sort, Doc) ->
     #cacc{
         limit = Limit,
         skip = Skip,
-        execution_stats = Stats,
+        execution_stats = Stats0,
         documents_seen = Seen
     } = CAcc0,
     CAcc1 = update_bookmark(CAcc0, Sort),
-    Stats1 = mango_execution_stats:incr_docs_examined(Stats),
+    Stats1 = mango_execution_stats:incr_keys_examined(Stats0),
+    Stats = mango_execution_stats:incr_docs_examined(Stats1),
     couch_stats:increment_counter([mango, docs_examined]),
-    CAcc2 = CAcc1#cacc{execution_stats = Stats1},
+    CAcc2 = CAcc1#cacc{execution_stats = Stats},
     case mango_selector:match(CAcc2#cacc.selector, Doc) of
         true ->
             DocId = mango_doc:get_field(Doc, <<"_id">>),
@@ -430,8 +431,18 @@ execute_test_() ->
         foreach,
         fun() ->
             meck:new(foo, [non_strict]),
+            meck:new(couch_stats),
             meck:expect(couch_db, name, [db], meck:val(db_name)),
-            meck:expect(couch_stats, increment_counter, [[mango, 
docs_examined]], meck:val(ok)),
+            meck:expect(
+                couch_stats,
+                increment_counter,
+                [
+                    {[[mango, docs_examined]], meck:val(ok)},
+                    {[[mango, results_returned]], meck:val(ok)},
+                    {[[couch_log, level, report]], meck:val(ok)}
+                ]
+            ),
+            meck:expect(couch_stats, update_histogram, [[mango, query_time], 
'_'], meck:val(ok)),
             % Dummy mock functions to progressively update the
             % respective states therefore their results could be
             % asserted later on.
@@ -466,28 +477,6 @@ execute_test_() ->
                     {ok, IdDocs}
                 end
             ),
-            meck:expect(mango_execution_stats, log_start, [stats], 
meck:val({stats, 0})),
-            meck:expect(
-                mango_execution_stats,
-                maybe_add_stats,
-                fun(_Options, _UserFun, {stats, N}, {acc, M}) -> {{acc, M + 
1}, {stats, N + 1}} end
-            ),
-            meck:expect(mango_execution_stats, log_stats, [{stats, '_'}], 
meck:val(ok)),
-            meck:expect(
-                mango_cursor,
-                maybe_add_warning,
-                fun(_UserFun, _Cursor, {stats, _}, {acc, M}) -> {acc, M + 1} 
end
-            ),
-            meck:expect(
-                mango_execution_stats,
-                incr_docs_examined,
-                fun({stats, N}) -> {stats, N + 1} end
-            ),
-            meck:expect(
-                mango_execution_stats,
-                incr_results_returned,
-                fun({stats, N}) -> {stats, N + 1} end
-            ),
             meck:expect(
                 mango_selector_text,
                 append_sort_type,
@@ -541,13 +530,14 @@ t_execute_empty(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(mango_selector_text, convert, [selector], meck:val(<<>>)),
-    ?assertEqual({ok, {acc, 3}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
-    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [0], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [0], meck:val(ok)),
+    ?assertEqual({ok, {acc, 1}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
+    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])),
+    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])).
 
 t_execute_no_results(_) ->
     Limit = 10,
@@ -564,7 +554,7 @@ t_execute_no_results(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     QueryArgs =
         #index_query_args{
@@ -583,13 +573,13 @@ t_execute_no_results(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 3}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
-    ?assertEqual(0, meck:num_calls(dreyfus_fabric, get_json_docs, 2)),
-    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [0], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [0], meck:val(ok)),
+    ?assertEqual({ok, {acc, 1}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
+    ?assertEqual(0, meck:num_calls(dreyfus_fabric, get_json_docs, 2)).
 
 t_execute_more_results(_) ->
+    AllHits = 3,
     Options = [{partition, partition}, {sort, {[]}}, {bookmark, [bookmark, 
0]}],
     Cursor = #cursor{
         db = db,
@@ -599,7 +589,7 @@ t_execute_more_results(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -631,12 +621,16 @@ t_execute_more_results(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 6}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(3, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(3, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(3, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [AllHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [AllHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
+    ?assertEqual(
+        AllHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_unique_results(_) ->
+    AllHits = 6,
     UniqueHits = 3,
     Options = [{partition, partition}, {sort, {[]}}, {bookmark, []}],
     Cursor = #cursor{
@@ -647,7 +641,7 @@ t_execute_unique_results(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -680,10 +674,13 @@ t_execute_unique_results(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 6}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(6, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(6, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [AllHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [AllHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_limit_cutoff(_) ->
     Limit = 2,
@@ -699,7 +696,7 @@ t_execute_limit_cutoff(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     QueryArgs =
         #index_query_args{
@@ -722,10 +719,13 @@ t_execute_limit_cutoff(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 5}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(Limit, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(Limit, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(Limit, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [Limit], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [Limit], meck:val(ok)),
+    ?assertEqual({ok, {acc, 3}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(Limit, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
+    ?assertEqual(
+        Limit, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_limit_cutoff_unique(_) ->
     Limit = 4,
@@ -740,7 +740,7 @@ t_execute_limit_cutoff_unique(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -773,10 +773,13 @@ t_execute_limit_cutoff_unique(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 6}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(AllHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(ActualHits, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [AllHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [AllHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
+    ?assertEqual(
+        ActualHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_limit_zero(_) ->
     Limit = 0,
@@ -791,7 +794,7 @@ t_execute_limit_zero(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     QueryArgs =
         #index_query_args{
@@ -814,10 +817,13 @@ t_execute_limit_zero(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 3}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
-    ?assertEqual(1, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(1, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(Limit, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [Limit], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [Limit], meck:val(ok)),
+    ?assertEqual({ok, {acc, 1}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
+    ?assertEqual(1, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])),
+    ?assertEqual(
+        Limit, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_limit_unique(_) ->
     Limit = 5,
@@ -832,7 +838,7 @@ t_execute_limit_unique(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -865,10 +871,13 @@ t_execute_limit_unique(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 6}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(AllHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [AllHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [AllHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_skip(_) ->
     UniqueHits = 3,
@@ -882,7 +891,7 @@ t_execute_skip(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -910,11 +919,15 @@ t_execute_skip(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(UniqueHits, meck:num_calls(couch_stats, increment_counter, 
1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
+    meck:expect(chttpd_stats, incr_rows, [UniqueHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [UniqueHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 2}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
     ?assertEqual(
-        UniqueHits - Skip, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])
+    ),
+    ?assertEqual(
+        UniqueHits - Skip,
+        meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
     ).
 
 t_execute_skip_unique(_) ->
@@ -930,7 +943,7 @@ t_execute_skip_unique(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -963,11 +976,13 @@ t_execute_skip_unique(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> true end),
-    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(AllHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
+    meck:expect(chttpd_stats, incr_rows, [AllHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [AllHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 2}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(AllHits, meck:num_calls(couch_stats, increment_counter, 
[[mango, docs_examined]])),
     ?assertEqual(
-        UniqueHits - Skip, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)
+        UniqueHits - Skip,
+        meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
     ).
 
 t_execute_no_matches(_) ->
@@ -982,7 +997,7 @@ t_execute_no_matches(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -1010,10 +1025,15 @@ t_execute_no_matches(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, _}) -> false end),
-    ?assertEqual({ok, {acc, 3}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
-    ?assertEqual(UniqueHits, meck:num_calls(couch_stats, increment_counter, 
1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(Matches, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [UniqueHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [UniqueHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 1}}, execute(Cursor, fun foo:add_key_only/2, {acc, 
0})),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])
+    ),
+    ?assertEqual(
+        Matches, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_mixed_matches(_) ->
     UniqueHits = 3,
@@ -1027,7 +1047,7 @@ t_execute_mixed_matches(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     meck:expect(
         dreyfus_fabric_search,
@@ -1055,10 +1075,15 @@ t_execute_mixed_matches(_) ->
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
     meck:expect(mango_selector, match, fun(selector, {doc, N}) -> N == 2 end),
-    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
-    ?assertEqual(UniqueHits, meck:num_calls(couch_stats, increment_counter, 
1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(Matches, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [UniqueHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [UniqueHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 2}}, execute(Cursor, fun foo:normal/2, {acc, 0})),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])
+    ),
+    ?assertEqual(
+        Matches, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_user_fun_returns_stop(_) ->
     UniqueHits = 3,
@@ -1075,7 +1100,7 @@ t_execute_user_fun_returns_stop(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     QueryArgs =
         #index_query_args{
@@ -1114,10 +1139,15 @@ t_execute_user_fun_returns_stop(_) ->
             {Status, {acc, N + 1}}
         end
     ),
-    ?assertEqual({ok, {acc, 6}}, execute(Cursor, fun foo:stops/2, {acc, 0})),
-    ?assertEqual(UniqueHits, meck:num_calls(couch_stats, increment_counter, 
1)),
-    ?assertEqual(UniqueHits, meck:num_calls(mango_execution_stats, 
incr_docs_examined, 1)),
-    ?assertEqual(3, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    meck:expect(chttpd_stats, incr_rows, [UniqueHits], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [UniqueHits], meck:val(ok)),
+    ?assertEqual({ok, {acc, 4}}, execute(Cursor, fun foo:stops/2, {acc, 0})),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])
+    ),
+    ?assertEqual(
+        UniqueHits, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])
+    ).
 
 t_execute_search_error(_) ->
     Limit = 10,
@@ -1133,7 +1163,7 @@ t_execute_search_error(_) ->
         fields = fields,
         selector = selector,
         opts = Options,
-        execution_stats = stats
+        execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
     },
     QueryArgs =
         #index_query_args{
@@ -1151,13 +1181,14 @@ t_execute_search_error(_) ->
         meck:val({error, reason})
     ),
     meck:expect(mango_selector_text, convert, [selector], meck:val(query)),
+    meck:expect(chttpd_stats, incr_rows, [0], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [0], meck:val(ok)),
     Exception = {mango_error, mango_cursor_text, {text_search_error, {error, 
reason}}},
     ?assertThrow(Exception, execute(Cursor, fun foo:normal/2, {acc, 0})),
     ?assertEqual(0, meck:num_calls(dreyfus_fabric, get_json_docs, 2)),
     ?assertEqual(0, meck:num_calls(foo, normal, 2)),
-    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, 1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, incr_docs_examined, 
1)),
-    ?assertEqual(0, meck:num_calls(mango_execution_stats, 
incr_results_returned, 1)).
+    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, [[mango, 
docs_examined]])),
+    ?assertEqual(0, meck:num_calls(couch_stats, increment_counter, [[mango, 
results_returned]])).
 
 explain_test_() ->
     {
diff --git a/src/mango/src/mango_cursor_view.erl 
b/src/mango/src/mango_cursor_view.erl
index b1357ac68..b103d869d 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -992,12 +992,10 @@ execute_test_() ->
         foreach,
         fun() ->
             meck:new(foo, [non_strict]),
-            meck:new(fabric)
-        end,
-        fun(_) ->
-            meck:unload(fabric),
-            meck:unload(foo)
+            meck:new(fabric),
+            meck:new(chttpd_stats)
         end,
+        fun(_) -> meck:unload() end,
         [
             ?TDEF_FE(t_execute_empty),
             ?TDEF_FE(t_execute_ok_all_docs),
@@ -1014,7 +1012,9 @@ t_execute_empty(_) ->
     meck:expect(fabric, query_view, ['_', '_', '_', '_', '_', '_'], 
meck:val(error)),
     ?assertEqual({ok, accumulator}, execute(Cursor, undefined, accumulator)),
     ?assertNot(meck:called(fabric, all_docs, '_')),
-    ?assertNot(meck:called(fabric, query_view, '_')).
+    ?assertNot(meck:called(fabric, query_view, '_')),
+    ?assertNot(meck:called(chttpd_stats, incr_rows, '_')),
+    ?assertNot(meck:called(chttpd_stats, incr_reads, '_')).
 
 t_execute_ok_all_docs(_) ->
     Bookmark = bookmark,
@@ -1039,12 +1039,19 @@ t_execute_ok_all_docs(_) ->
             user_fun = fun foo:bar/2,
             execution_stats = '_'
         },
+    TotalKeysExamined = 9,
+    TotalDocsExamined = 3,
     Cursor2 =
         Cursor1#cursor{
             bookmark = Bookmark,
             bookmark_docid = undefined,
             bookmark_key = undefined,
-            execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
+            execution_stats =
+                #execution_stats{
+                    totalKeysExamined = TotalKeysExamined,
+                    totalDocsExamined = TotalDocsExamined,
+                    executionStartTime = {0, 0, 0}
+                }
         },
     Extra =
         [
@@ -1071,13 +1078,25 @@ t_execute_ok_all_docs(_) ->
         db, [{user_ctx, user_ctx}], fun 
mango_cursor_view:handle_all_docs_message/2, Cursor1, Args
     ],
     meck:expect(fabric, all_docs, Parameters, meck:val({ok, Cursor2})),
+    meck:expect(chttpd_stats, incr_rows, [TotalKeysExamined], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [TotalDocsExamined], meck:val(ok)),
     ?assertEqual({ok, updated_accumulator}, execute(Cursor, fun foo:bar/2, 
accumulator)),
     ?assert(meck:called(fabric, all_docs, '_')).
 
 t_execute_ok_query_view(_) ->
     Bookmark = bookmark,
-    UserFnParameters = [{add_key, bookmark, Bookmark}, accumulator],
-    meck:expect(foo, bar, UserFnParameters, meck:val({undefined, 
updated_accumulator})),
+    UserFnParameters1 = [{add_key, bookmark, Bookmark}, accumulator1],
+    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],
+    meck:expect(
+        foo,
+        bar,
+        [
+            {UserFnParameters1, meck:val({undefined, accumulator2})},
+            {UserFnParameters2, meck:val({undefined, accumulator3})}
+        ]
+    ),
     Index =
         #idx{
             type = <<"json">>,
@@ -1099,16 +1118,23 @@ t_execute_ok_query_view(_) ->
         },
     Cursor1 =
         Cursor#cursor{
-            user_acc = accumulator,
+            user_acc = accumulator1,
             user_fun = fun foo:bar/2,
             execution_stats = '_'
         },
+    TotalKeysExamined = 99,
+    TotalDocsExamined = 33,
     Cursor2 =
         Cursor1#cursor{
             bookmark = Bookmark,
             bookmark_docid = undefined,
             bookmark_key = undefined,
-            execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
+            execution_stats =
+                #execution_stats{
+                    totalKeysExamined = TotalKeysExamined,
+                    totalDocsExamined = TotalDocsExamined,
+                    executionStartTime = {0, 0, 0}
+                }
         },
     Extra =
         [
@@ -1141,17 +1167,31 @@ t_execute_ok_query_view(_) ->
         Args
     ],
     meck:expect(fabric, query_view, Parameters, meck:val({ok, Cursor2})),
-    ?assertEqual({ok, updated_accumulator}, execute(Cursor, fun foo:bar/2, 
accumulator)),
+    meck:expect(chttpd_stats, incr_rows, [TotalKeysExamined], meck:val(ok)),
+    meck:expect(chttpd_stats, incr_reads, [TotalDocsExamined], meck:val(ok)),
+    ?assertEqual({ok, accumulator3}, execute(Cursor, fun foo:bar/2, 
accumulator1)),
     ?assert(meck:called(fabric, query_view, '_')).
 
 t_execute_ok_all_docs_with_execution_stats(_) ->
     Bookmark = bookmark,
+    TotalKeysExamined = 33,
+    TotalDocsExamined = 12,
+    TotalQuorumDocsExamined = 0,
+    ResultsReturned = 20,
+    ExecutionStats =
+        #execution_stats{
+            totalKeysExamined = TotalKeysExamined,
+            totalDocsExamined = TotalDocsExamined,
+            totalQuorumDocsExamined = TotalQuorumDocsExamined,
+            resultsReturned = ResultsReturned,
+            executionStartTime = {0, 0, 0}
+        },
     Stats =
         {[
-            {total_keys_examined, 0},
-            {total_docs_examined, 0},
-            {total_quorum_docs_examined, 0},
-            {results_returned, 0},
+            {total_keys_examined, TotalKeysExamined},
+            {total_docs_examined, TotalDocsExamined},
+            {total_quorum_docs_examined, TotalQuorumDocsExamined},
+            {results_returned, ResultsReturned},
             {execution_time_ms, '_'}
         ]},
     UserFnDefinition =
@@ -1187,7 +1227,7 @@ t_execute_ok_all_docs_with_execution_stats(_) ->
             bookmark = Bookmark,
             bookmark_docid = undefined,
             bookmark_key = undefined,
-            execution_stats = #execution_stats{executionStartTime = {0, 0, 0}}
+            execution_stats = ExecutionStats
         },
     Extra =
         [
@@ -1213,6 +1253,8 @@ 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: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(fabric, all_docs, '_')).
@@ -1232,7 +1274,9 @@ t_execute_error_1(_) ->
         db, '_', <<"ghibli">>, index_name, fun 
mango_cursor_view:handle_message/2, '_', '_'
     ],
     meck:expect(fabric, query_view, Parameters, meck:val({error, reason})),
-    ?assertEqual({error, reason}, execute(Cursor, undefined, accumulator)).
+    ?assertEqual({error, reason}, execute(Cursor, undefined, accumulator)),
+    ?assertNot(meck:called(chttpd_stats, incr_rows, '_')),
+    ?assertNot(meck:called(chttpd_stats, incr_reads, '_')).
 
 t_execute_error_2(_) ->
     Cursor =
@@ -1249,7 +1293,9 @@ t_execute_error_2(_) ->
         db, '_', <<"ghibli">>, index_name, fun 
mango_cursor_view:handle_message/2, '_', '_'
     ],
     meck:expect(fabric, query_view, Parameters, meck:val({ok, {error, 
reason}})),
-    ?assertEqual({error, {error, reason}}, execute(Cursor, undefined, 
accumulator)).
+    ?assertEqual({error, {error, reason}}, execute(Cursor, undefined, 
accumulator)),
+    ?assertNot(meck:called(chttpd_stats, incr_rows, '_')),
+    ?assertNot(meck:called(chttpd_stats, incr_reads, '_')).
 
 view_cb_test_() ->
     {
diff --git a/src/mango/src/mango_execution_stats.erl 
b/src/mango/src/mango_execution_stats.erl
index 350b58bda..dce7c087b 100644
--- a/src/mango/src/mango_execution_stats.erl
+++ b/src/mango/src/mango_execution_stats.erl
@@ -15,6 +15,7 @@
 -export([
     to_json/1,
     to_map/1,
+    incr_keys_examined/1,
     incr_keys_examined/2,
     incr_docs_examined/1,
     incr_docs_examined/2,
@@ -53,6 +54,9 @@ to_map(Stats) ->
         execution_time_ms => Stats#execution_stats.executionTimeMs
     }.
 
+incr_keys_examined(Stats) ->
+    incr_keys_examined(Stats, 1).
+
 incr_keys_examined(Stats, N) ->
     Stats#execution_stats{
         totalKeysExamined = Stats#execution_stats.totalKeysExamined + N
@@ -92,8 +96,8 @@ log_end(Stats) ->
 maybe_add_stats(Opts, UserFun, Stats0, UserAcc) ->
     Stats1 = log_end(Stats0),
     couch_stats:update_histogram([mango, query_time], 
Stats1#execution_stats.executionTimeMs),
-    %% TODO: add rows read when we collect the stats
     %% TODO: add docs vs quorum docs
+    chttpd_stats:incr_rows(Stats1#execution_stats.totalKeysExamined),
     chttpd_stats:incr_reads(Stats1#execution_stats.totalDocsExamined),
 
     FinalAcc =
diff --git a/src/mango/test/15-execution-stats-test.py 
b/src/mango/test/15-execution-stats-test.py
index a8f996136..caa542d7a 100644
--- a/src/mango/test/15-execution-stats-test.py
+++ b/src/mango/test/15-execution-stats-test.py
@@ -81,7 +81,7 @@ class ExecutionStatsTests_Text(mango.UserDocsTextTests):
             {"$text": "Stephanie"}, return_raw=True, executionStats=True
         )
         self.assertEqual(len(resp["docs"]), 1)
-        self.assertEqual(resp["execution_stats"]["total_keys_examined"], 0)
+        self.assertEqual(resp["execution_stats"]["total_keys_examined"], 1)
         self.assertEqual(resp["execution_stats"]["total_docs_examined"], 1)
         
self.assertEqual(resp["execution_stats"]["total_quorum_docs_examined"], 0)
         self.assertEqual(resp["execution_stats"]["results_returned"], 1)

Reply via email to