You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by wi...@apache.org on 2020/01/07 15:32:21 UTC
[couchdb] 01/01: Fix missing mango execution stats
This is an automated email from the ASF dual-hosted git repository.
willholley pushed a commit to branch fix_mango_execution_stats
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 9213fd0e7db03a49ca42ab03ea2a8393869664e1
Author: Will Holley <wi...@gmail.com>
AuthorDate: Tue Jan 7 13:40:32 2020 +0000
Fix missing mango execution stats
The previous implementation of Mango execution stats relied on
passing the docs_examined count from each shard to the coordinator
in the view_row record. This failed to collect the count of
documents read which weren't followed by a match (in a given shard).
For example, if an index was scanned but no documents were matched,
the docs_examined would be 0, when it should be equal to the number
of documents in the index.
This commit changes the implementation so that docs examined is passed
only when each shard has completed its index scan. This requires a new
handler in fabric so, in it's current state, will generate errors
in mixed-version clusters.
---
src/fabric/src/fabric_view_all_docs.erl | 7 +++-
src/fabric/src/fabric_view_map.erl | 6 +++
src/mango/src/mango_cursor_view.erl | 65 ++++++++++++++-----------------
src/mango/test/15-execution-stats-test.py | 4 ++
4 files changed, 45 insertions(+), 37 deletions(-)
diff --git a/src/fabric/src/fabric_view_all_docs.erl b/src/fabric/src/fabric_view_all_docs.erl
index 07cd1b1..e4d3d4a 100644
--- a/src/fabric/src/fabric_view_all_docs.erl
+++ b/src/fabric/src/fabric_view_all_docs.erl
@@ -239,8 +239,13 @@ handle_message(#view_row{} = Row, {Worker, From}, State) ->
handle_message(complete, Worker, State) ->
Counters = fabric_dict:update_counter(Worker, 1, State#collector.counters),
- fabric_view:maybe_send_row(State#collector{counters = Counters}).
+ fabric_view:maybe_send_row(State#collector{counters = Counters});
+handle_message({execution_stats, _} = Msg, {_,From}, St) ->
+ #collector{callback=Callback, user_acc=AccIn} = St,
+ {Go, Acc} = Callback(Msg, AccIn),
+ rexi:stream_ack(From),
+ {Go, St#collector{user_acc=Acc}}.
merge_row(fwd, Row, Rows) ->
lists:keymerge(#view_row.id, [Row], Rows);
diff --git a/src/fabric/src/fabric_view_map.erl b/src/fabric/src/fabric_view_map.erl
index 5a5cc13..b8d0d39 100644
--- a/src/fabric/src/fabric_view_map.erl
+++ b/src/fabric/src/fabric_view_map.erl
@@ -180,6 +180,12 @@ handle_message(complete, Worker, State) ->
Counters = fabric_dict:update_counter(Worker, 1, State#collector.counters),
fabric_view:maybe_send_row(State#collector{counters = Counters});
+handle_message({execution_stats, _} = Msg, {_,From}, St) ->
+ #collector{callback=Callback, user_acc=AccIn} = St,
+ {Go, Acc} = Callback(Msg, AccIn),
+ rexi:stream_ack(From),
+ {Go, St#collector{user_acc=Acc}};
+
handle_message(ddoc_updated, _Worker, State) ->
{stop, State}.
diff --git a/src/mango/src/mango_cursor_view.erl b/src/mango/src/mango_cursor_view.erl
index 1c4b342..5da5737 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -44,7 +44,7 @@ create(Db, Indexes, Selector, Opts) ->
Limit = couch_util:get_value(limit, Opts, mango_opts:default_limit()),
Skip = couch_util:get_value(skip, Opts, 0),
Fields = couch_util:get_value(fields, Opts, all_fields),
- Bookmark = couch_util:get_value(bookmark, Opts),
+ Bookmark = couch_util:get_value(bookmark, Opts),
{ok, #cursor{
db = Db,
@@ -124,7 +124,7 @@ execute(#cursor{db = Db, index = Idx, execution_stats = Stats} = Cursor0, UserFu
BaseArgs = base_args(Cursor),
#cursor{opts = Opts, bookmark = Bookmark} = Cursor,
Args0 = apply_opts(Opts, BaseArgs),
- Args = mango_json_bookmark:update_args(Bookmark, Args0),
+ Args = mango_json_bookmark:update_args(Bookmark, Args0),
UserCtx = couch_util:get_value(user_ctx, Opts, #user_ctx{}),
DbOpts = [{user_ctx, UserCtx}],
Result = case mango_idx:def(Idx) of
@@ -231,32 +231,26 @@ view_cb({row, Row}, #mrargs{extra = Options} = Acc) ->
},
case ViewRow#view_row.doc of
null ->
- put(mango_docs_examined, get(mango_docs_examined) + 1),
maybe_send_mango_ping();
undefined ->
- ViewRow2 = ViewRow#view_row{
- value = couch_util:get_value(value, Row)
- },
- ok = rexi:stream2(ViewRow2),
- put(mango_docs_examined, 0),
+ % include_docs=false. Use quorum fetch at coordinator
+ ok = rexi:stream2(ViewRow),
set_mango_msg_timestamp();
Doc ->
+ put(mango_docs_examined, get(mango_docs_examined) + 1),
Selector = couch_util:get_value(selector, Options),
case mango_selector:match(Selector, Doc) of
true ->
- ViewRow2 = ViewRow#view_row{
- value = get(mango_docs_examined) + 1
- },
- ok = rexi:stream2(ViewRow2),
- put(mango_docs_examined, 0),
+ ok = rexi:stream2(ViewRow),
set_mango_msg_timestamp();
false ->
- put(mango_docs_examined, get(mango_docs_examined) + 1),
maybe_send_mango_ping()
end
end,
{ok, Acc};
view_cb(complete, Acc) ->
+ % Send shard-level execution stats
+ ok = rexi:stream2({execution_stats, {docs_examined, get(mango_docs_examined)}}),
% Finish view output
ok = rexi:stream_last(complete),
{ok, Acc};
@@ -286,22 +280,28 @@ handle_message({meta, _}, Cursor) ->
{ok, Cursor};
handle_message({row, Props}, Cursor) ->
case doc_member(Cursor, Props) of
- {ok, Doc, {execution_stats, ExecutionStats1}} ->
+ {ok, Doc, {execution_stats, Stats}} ->
Cursor1 = Cursor#cursor {
- execution_stats = ExecutionStats1
+ execution_stats = Stats
},
Cursor2 = update_bookmark_keys(Cursor1, Props),
FinalDoc = mango_fields:extract(Doc, Cursor2#cursor.fields),
handle_doc(Cursor2, FinalDoc);
- {no_match, _, {execution_stats, ExecutionStats1}} ->
+ {no_match, _, {execution_stats, Stats}} ->
Cursor1 = Cursor#cursor {
- execution_stats = ExecutionStats1
+ execution_stats = Stats
},
{ok, Cursor1};
Error ->
couch_log:error("~s :: Error loading doc: ~p", [?MODULE, Error]),
{ok, Cursor}
end;
+handle_message({execution_stats, ShardStats}, #cursor{execution_stats = Stats} = Cursor) ->
+ {docs_examined, DocsExamined} = ShardStats,
+ Cursor1 = Cursor#cursor{
+ execution_stats = mango_execution_stats:incr_docs_examined(Stats, DocsExamined)
+ },
+ {ok, Cursor1};
handle_message(complete, Cursor) ->
{ok, Cursor};
handle_message({error, Reason}, _Cursor) ->
@@ -410,24 +410,18 @@ apply_opts([{_, _} | Rest], Args) ->
doc_member(Cursor, RowProps) ->
- Db = Cursor#cursor.db,
+ Db = Cursor#cursor.db,
Opts = Cursor#cursor.opts,
ExecutionStats = Cursor#cursor.execution_stats,
Selector = Cursor#cursor.selector,
- {Matched, Incr} = case couch_util:get_value(value, RowProps) of
- N when is_integer(N) -> {true, N};
- _ -> {false, 1}
- end,
case couch_util:get_value(doc, RowProps) of
{DocProps} ->
- ExecutionStats1 = mango_execution_stats:incr_docs_examined(ExecutionStats, Incr),
- case Matched of
- true ->
- {ok, {DocProps}, {execution_stats, ExecutionStats1}};
- false ->
- match_doc(Selector, {DocProps}, ExecutionStats1)
- end;
+ % only matching documents are returned; the selector
+ % is evaluated at the shard level in view_cb({row, Row},
+ {ok, {DocProps}, {execution_stats, ExecutionStats}};
undefined ->
+ % an undefined doc was returned, indicating we should
+ % perform a quorum fetch
ExecutionStats1 = mango_execution_stats:incr_quorum_docs_examined(ExecutionStats),
Id = couch_util:get_value(id, RowProps),
case mango_util:defer(fabric, open_doc, [Db, Id, Opts]) of
@@ -437,9 +431,9 @@ doc_member(Cursor, RowProps) ->
Else ->
Else
end;
- null ->
- ExecutionStats1 = mango_execution_stats:incr_docs_examined(ExecutionStats),
- {no_match, null, {execution_stats, ExecutionStats1}}
+ _ ->
+ % no doc, no match
+ {no_match, null, {execution_stats, ExecutionStats}}
end.
@@ -460,8 +454,8 @@ is_design_doc(RowProps) ->
update_bookmark_keys(#cursor{limit = Limit} = Cursor, Props) when Limit > 0 ->
- Id = couch_util:get_value(id, Props),
- Key = couch_util:get_value(key, Props),
+ Id = couch_util:get_value(id, Props),
+ Key = couch_util:get_value(key, Props),
Cursor#cursor {
bookmark_docid = Id,
bookmark_key = Key
@@ -506,7 +500,6 @@ does_not_run_match_on_doc_with_value_test() ->
RowProps = [
{id,<<"b06aadcf-cd0f-4ca6-9f7e-2c993e48d4c4">>},
{key,<<"b06aadcf-cd0f-4ca6-9f7e-2c993e48d4c4">>},
- {value,1},
{doc,{
[
{<<"_id">>,<<"b06aadcf-cd0f-4ca6-9f7e-2c993e48d4c4">>},
diff --git a/src/mango/test/15-execution-stats-test.py b/src/mango/test/15-execution-stats-test.py
index 922cadf..d3687f8 100644
--- a/src/mango/test/15-execution-stats-test.py
+++ b/src/mango/test/15-execution-stats-test.py
@@ -53,6 +53,10 @@ class ExecutionStatsTests(mango.UserDocsTests):
)
self.assertEqual(resp["execution_stats"]["results_returned"], len(resp["docs"]))
+ def test_no_matches_index_scan(self):
+ resp = self.db.find({"age": {"$lt": 35}, "nomatch": "me"}, return_raw=True, executionStats=True)
+ self.assertEqual(resp["execution_stats"]["total_docs_examined"], 3)
+ self.assertEqual(resp["execution_stats"]["results_returned"], 0)
@unittest.skipUnless(mango.has_text_service(), "requires text service")
class ExecutionStatsTests_Text(mango.UserDocsTextTests):