blob: 350b58bdacc3df860b6d0e12d1ee95ce837cb316 [file] [log] [blame]
% 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(mango_execution_stats).
-export([
to_json/1,
to_map/1,
incr_keys_examined/2,
incr_docs_examined/1,
incr_docs_examined/2,
incr_quorum_docs_examined/1,
incr_results_returned/1,
log_start/1,
log_end/1,
log_stats/1,
maybe_add_stats/4,
shard_init/0,
shard_incr_keys_examined/0,
shard_incr_docs_examined/0,
shard_get_stats/0
]).
-include("mango.hrl").
-include("mango_cursor.hrl").
-define(SHARD_STATS_KEY, mango_shard_execution_stats).
to_json(Stats) ->
{[
{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}
]}.
to_map(Stats) ->
#{
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
}.
incr_keys_examined(Stats, N) ->
Stats#execution_stats{
totalKeysExamined = Stats#execution_stats.totalKeysExamined + N
}.
incr_docs_examined(Stats) ->
incr_docs_examined(Stats, 1).
incr_docs_examined(Stats, N) ->
Stats#execution_stats{
totalDocsExamined = Stats#execution_stats.totalDocsExamined + N
}.
incr_quorum_docs_examined(Stats) ->
Stats#execution_stats{
totalQuorumDocsExamined = Stats#execution_stats.totalQuorumDocsExamined + 1
}.
incr_results_returned(Stats) ->
couch_stats:increment_counter([mango, results_returned]),
Stats#execution_stats{
resultsReturned = Stats#execution_stats.resultsReturned + 1
}.
log_start(Stats) ->
Stats#execution_stats{
executionStartTime = os:timestamp()
}.
log_end(Stats) ->
End = os:timestamp(),
Diff = timer:now_diff(End, Stats#execution_stats.executionStartTime) / 1000,
Stats#execution_stats{
executionTimeMs = Diff
}.
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_reads(Stats1#execution_stats.totalDocsExamined),
FinalAcc =
case couch_util:get_value(execution_stats, Opts) of
true ->
JSONValue = to_json(Stats1),
Arg = {add_key, execution_stats, JSONValue},
{_Go, FinalUserAcc} = UserFun(Arg, UserAcc),
FinalUserAcc;
_ ->
UserAcc
end,
{FinalAcc, Stats1}.
log_stats(Stats) ->
MStats0 = to_map(Stats),
Nonce = list_to_binary(couch_log_util:get_msg_id()),
MStats1 = MStats0#{nonce => Nonce},
couch_log:report("mango-stats", MStats1).
-spec shard_init() -> any().
shard_init() ->
InitialState = #{docs_examined => 0, keys_examined => 0},
put(?SHARD_STATS_KEY, InitialState).
-spec shard_incr_keys_examined() -> any().
shard_incr_keys_examined() ->
incr(keys_examined).
-spec shard_incr_docs_examined() -> any().
shard_incr_docs_examined() ->
incr(docs_examined).
-spec incr(atom()) -> any().
incr(Key) ->
case get(?SHARD_STATS_KEY) of
#{} = Stats0 ->
Stats = maps:update_with(Key, fun(X) -> X + 1 end, Stats0),
put(?SHARD_STATS_KEY, Stats);
_ ->
ok
end.
-spec shard_get_stats() -> shard_stats_v2().
shard_get_stats() ->
get(?SHARD_STATS_KEY).