Skip to content

Commit

Permalink
Optimize couch_util:reorder_results/2,3
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nickva committed Jun 7, 2022
1 parent 14a5213 commit a1fc807
Showing 1 changed file with 4 additions and 15 deletions.
19 changes: 4 additions & 15 deletions src/couch/src/couch_util.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit a1fc807

Please sign in to comment.