diff options
author | Nick Vatamaniuc <vatamane@gmail.com> | 2022-06-07 10:30:03 -0400 |
---|---|---|
committer | Nick Vatamaniuc <nickva@users.noreply.github.com> | 2022-06-07 13:49:21 -0400 |
commit | a1fc8075f3e86ec2242eedd2b1bbbd15758515e7 (patch) | |
tree | 168f96a5b912adcb8602cacb179d55699b73b271 | |
parent | 14a5213470f9372b2d97af0bfc214f438d059132 (diff) | |
download | couchdb-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.erl | 19 |
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( |