Instrument Mango execution stats

Adds metrics for mango execution statistics:
 * total docs examined (counter). Note that for non-quorum doc
   reads this needs to be counted at the shard level and not be the
   mango query coordinator
 * total results returned (counter)
 * query time (histogram)
 * mango:selector evaluations (may be queries or _changes feeds)

For mrview-based queries which don't use quorum reads (the default),
total docs examined should equal mango:selector evaluations. However,
there are cases where mango selectors are evaluated outside of query
time e.g. partial indexing, selector-based _changes which make it
useful to maintain a distinct counter.
diff --git a/src/couch/priv/stats_descriptions.cfg b/src/couch/priv/stats_descriptions.cfg
index 557ac36..7c8fd94 100644
--- a/src/couch/priv/stats_descriptions.cfg
+++ b/src/couch/priv/stats_descriptions.cfg
@@ -310,3 +310,23 @@
     {type, counter},
     {desc, <<"number of mango queries that generated an index scan warning">>}
 ]}.
+{[mango, docs_examined], [
+    {type, counter},
+    {desc, <<"number of documents examined by mango queries coordinated by this node">>}
+]}.
+{[mango, quorum_docs_examined], [
+    {type, counter},
+    {desc, <<"number of documents examined by mango queries, using cluster quorum">>}
+]}.
+{[mango, results_returned], [
+    {type, counter},
+    {desc, <<"number of rows returned by mango queries">>}
+]}.
+{[mango, query_time], [
+    {type, histogram},
+    {desc, <<"length of time processing a mango query">>}
+]}.
+{[mango, evaluate_selector], [
+    {type, counter},
+    {desc, <<"number of mango selector evaluations">>}
+]}.
diff --git a/src/mango/src/mango_cursor_text.erl b/src/mango/src/mango_cursor_text.erl
index 6b202da..2b42c39 100644
--- a/src/mango/src/mango_cursor_text.erl
+++ b/src/mango/src/mango_cursor_text.erl
@@ -184,6 +184,7 @@
     } = CAcc0,
     CAcc1 = update_bookmark(CAcc0, Sort),
     Stats1 = mango_execution_stats:incr_docs_examined(Stats),
+    couch_stats:increment_counter([mango, docs_examined]),
     CAcc2 = CAcc1#cacc{execution_stats = Stats1},
     case mango_selector:match(CAcc2#cacc.selector, Doc) of
         true when Skip > 0 ->
diff --git a/src/mango/src/mango_cursor_view.erl b/src/mango/src/mango_cursor_view.erl
index 2569469..240ef50 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -249,6 +249,7 @@
         Doc ->
             put(mango_docs_examined, get(mango_docs_examined) + 1),
             Selector = couch_util:get_value(selector, Options),
+            couch_stats:increment_counter([mango, docs_examined]),
             case mango_selector:match(Selector, Doc) of
                 true ->
                     ok = rexi:stream2(ViewRow),
@@ -433,6 +434,7 @@
             % an undefined doc was returned, indicating we should
             % perform a quorum fetch
             ExecutionStats1 = mango_execution_stats:incr_quorum_docs_examined(ExecutionStats),
+            couch_stats:increment_counter([mango, quorum_docs_examined]),
             Id = couch_util:get_value(id, RowProps),
             case mango_util:defer(fabric, open_doc, [Db, Id, Opts]) of
                 {ok, #doc{}=DocProps} ->
diff --git a/src/mango/src/mango_execution_stats.erl b/src/mango/src/mango_execution_stats.erl
index 7e8afd7..5878a31 100644
--- a/src/mango/src/mango_execution_stats.erl
+++ b/src/mango/src/mango_execution_stats.erl
@@ -62,6 +62,7 @@
 
 
 incr_results_returned(Stats) ->
+    couch_stats:increment_counter([mango, results_returned]),
     Stats#execution_stats {
         resultsReturned = Stats#execution_stats.resultsReturned + 1
     }.
@@ -81,11 +82,13 @@
     }.
 
 
-maybe_add_stats(Opts, UserFun, Stats, UserAcc) ->
+maybe_add_stats(Opts, UserFun, Stats0, UserAcc) ->
+    Stats1 = log_end(Stats0),
+    couch_stats:update_histogram([mango, query_time], Stats1#execution_stats.executionTimeMs),
+
     case couch_util:get_value(execution_stats, Opts) of
         true ->
-            Stats0 = log_end(Stats),
-            JSONValue = to_json(Stats0),
+            JSONValue = to_json(Stats1),
             Arg = {add_key, execution_stats, JSONValue},
             {_Go, FinalUserAcc} = UserFun(Arg, UserAcc),
             FinalUserAcc;
diff --git a/src/mango/src/mango_selector.erl b/src/mango/src/mango_selector.erl
index 005a6af..3ea83c2 100644
--- a/src/mango/src/mango_selector.erl
+++ b/src/mango/src/mango_selector.erl
@@ -52,15 +52,19 @@
 % Match a selector against a #doc{} or EJSON value.
 % This assumes that the Selector has been normalized.
 % Returns true or false.
+match(Selector, D) ->
+    couch_stats:increment_counter([mango, evaluate_selector]),
+    match_int(Selector, D).
+
 
 % An empty selector matches any value.
-match({[]}, _) ->
+match_int({[]}, _) ->
     true;
 
-match(Selector, #doc{body=Body}) ->
+match_int(Selector, #doc{body=Body}) ->
     match(Selector, Body, fun mango_json:cmp/2);
 
-match(Selector, {Props}) ->
+match_int(Selector, {Props}) ->
     match(Selector, {Props}, fun mango_json:cmp/2).
 
 % Convert each operator into a normalized version as well
@@ -582,7 +586,7 @@
     erlang:error({unnormalized_selector, Sel}).
 
 
-% Returns true if Selector requires all  
+% Returns true if Selector requires all
 % fields in RequiredFields to exist in any matching documents.
 
 % For each condition in the selector, check
@@ -612,13 +616,13 @@
 
 % We can "see" through $and operator. Iterate
 % through the list of child operators.
-has_required_fields_int([{[{<<"$and">>, Args}]}], RequiredFields) 
+has_required_fields_int([{[{<<"$and">>, Args}]}], RequiredFields)
         when is_list(Args) ->
     has_required_fields_int(Args, RequiredFields);
 
 % We can "see" through $or operator. Required fields
 % must be covered by all children.
-has_required_fields_int([{[{<<"$or">>, Args}]} | Rest], RequiredFields) 
+has_required_fields_int([{[{<<"$or">>, Args}]} | Rest], RequiredFields)
         when is_list(Args) ->
     Remainder0 = lists:foldl(fun(Arg, Acc) ->
         % for each child test coverage against the full
@@ -635,7 +639,7 @@
 
 % Handle $and operator where it has peers. Required fields
 % can be covered by any child.
-has_required_fields_int([{[{<<"$and">>, Args}]} | Rest], RequiredFields) 
+has_required_fields_int([{[{<<"$and">>, Args}]} | Rest], RequiredFields)
         when is_list(Args) ->
     Remainder = has_required_fields_int(Args, RequiredFields),
     has_required_fields_int(Rest, Remainder);