Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Even more scalable ETS ordered_set with write_concurrency #1997

Conversation

@sverker
Copy link
Contributor

@sverker sverker commented Oct 23, 2018

This is a continuation on #1952 by @kjellwinblad already merged to master for OTP-22.

#1952 introduced actual scalable write_concurrency for ordered_set tables with a novel data structure called contention adapting search tree.

The implementation did however use a fallback method for functions like ets:select accessing multiple keys, where all sub-trees were first merged into one and the old implementation then called. This PR lifts that restriction and all ets functions now operate on the contention adapting search tree without collapsing it.

Here are some benchmarks showing all access patterns now perform well, including those containing "selectAll" and "partial_select1000".

http://erlang.org/~sverker/ets_ordered_set_nomerge_select.html

sverker added 22 commits Oct 19, 2018
Move lookup from analyze_pattern to callers.
Brute force solution will always iterate tree from slot 0 and forward.

ToDo1: Yield.
ToDo2: Maybe optimize by caching AVL tree size in each base node.
{RouteNodes, BaseNodes, MaxRouteTreeDepth}
to easier generate a routing tree for test
without having to spend cpu to provoke actual repeated lock conflicts.
to not have to backtrack up on the stack.
Once an iteration key has been found, never fall back to first/last key in
next/prev tree as trees may split or join under our feet. I.e we must always
use previous key when searching for the next key.
to actually pass the copy to lock checker.
It's possible to first find an empty base node
and then retry and find the same base node as invalid.

It's a benign race with join which first makes the old invalid
'neighbor' accessible from 'gparent' before replacing it with
'new_neighbor'.
Easier to read and debug, and about the same lines of code.
sverker added 5 commits Oct 23, 2018
The original implementation did not do this due to fear of bad
performance. But we think the negative effect of "leaking" empty
base nodes is more important to fix.

To get the bad performance a special kind of access patterns is
needed where base nodes are frequently emptied and then repopulated
soon again. ets_SUITE:throughput_benchmark for example did not show
any negative effect from this commit at all.
We no longer lock more than one base node at a time.
We do however trylock a second base node at join.
sverker added 2 commits Oct 30, 2018
to generate a routing tree with keys that fit each test case.
to provoke iteration over a moving ordered_set with write_concurrency
and make sure we hit all "stable" keys.
@sverker sverker merged commit fa6994f into erlang:master Oct 31, 2018
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

1 participant