summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@gmail.com>2022-06-07 10:30:03 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2022-06-07 13:49:21 -0400
commita1fc8075f3e86ec2242eedd2b1bbbd15758515e7 (patch)
tree168f96a5b912adcb8602cacb179d55699b73b271
parent14a5213470f9372b2d97af0bfc214f438d059132 (diff)
downloadcouchdb-a1fc8075f3e86ec2242eedd2b1bbbd15758515e7.tar.gz
Optimize couch_util:reorder_results/2,3
This function is used in the hot path of _revs_diff and _bulk_docs API calls. Those could always use a bit more optimization: * In `_revs_diff` it's used when fetching all the FDIs to see which docs are missing in `couch_btree:lookup/2`. * In `_bulk_docs` it's used in the `fabric_doc_update` when finalizing the response. Using erlperf in #4051 noticed an at most 5x speedup from using a map instead of a dict. Since a map already falls back to a proplist for small sizes, skip the length guard. Some erlperf examples from #4051: 500 Keys ``` > f(Keys), f(Res), {Keys, Res} = Gen(500), ok. > erlperf:run(#{runner => {couch_util, reorder_results2, [Keys, Res, 100, dict]}}). 2407 > erlperf:run(#{runner => {couch_util, reorder_results2, [Keys, Res, 100, map]}}). 11639 ``` Using a map without the guard, which is the change in this this PR: ``` > f(Keys), f(Res), {Keys, Res} = Gen(500), ok. ok > erlperf:run(#{runner => {couch_util, reorder_results, [Keys, Res]}}). 12395 > erlperf:run(#{runner => {couch_util, reorder_results, [Keys, Res]}}). 12508 ``` As a bonus this also cleans up the code a bit, too.
-rw-r--r--src/couch/src/couch_util.erl19
1 files changed, 4 insertions, 15 deletions
diff --git a/src/couch/src/couch_util.erl b/src/couch/src/couch_util.erl
index e03a50e1d..912c6dd8a 100644
--- a/src/couch/src/couch_util.erl
+++ b/src/couch/src/couch_util.erl
@@ -523,24 +523,13 @@ verify(X, Y) when is_list(X) and is_list(Y) ->
verify(_X, _Y) ->
false.
-% linear search is faster for small lists, length() is 0.5 ms for 100k list
-reorder_results(Keys, SortedResults) when length(Keys) < 100 ->
- [couch_util:get_value(Key, SortedResults) || Key <- Keys];
reorder_results(Keys, SortedResults) ->
- KeyDict = dict:from_list(SortedResults),
- [dict:fetch(Key, KeyDict) || Key <- Keys].
+ Map = maps:from_list(SortedResults),
+ [maps:get(Key, Map) || Key <- Keys].
-reorder_results(Keys, SortedResults, Default) when length(Keys) < 100 ->
- [couch_util:get_value(Key, SortedResults, Default) || Key <- Keys];
reorder_results(Keys, SortedResults, Default) ->
- KeyDict = dict:from_list(SortedResults),
- DefaultFunc = fun({Key, Dict}) ->
- case dict:is_key(Key, Dict) of
- true -> dict:fetch(Key, Dict);
- false -> Default
- end
- end,
- [DefaultFunc({Key, KeyDict}) || Key <- Keys].
+ Map = maps:from_list(SortedResults),
+ [maps:get(Key, Map, Default) || Key <- Keys].
url_strip_password(Url) ->
re:replace(