Closed Terkwood closed 3 years ago
A better approach would be to use NIFs with resource objects. Resource objects allow you to associate a piece of native data with an opaque Erlang term. You can create a Rust struct containing a binary buffer (or any thing else), put that in a resource object, and use that as an argument to subsequent NIF calls.
This approach has many advantages, which includes very fast mutation and random access to the buffer, with no need to leave the current process.
Decent setup info here: https://www.kabisa.nl/tech/when-elixirs-performance-becomes-rust-y/
And read the manual's example: https://github.com/rusterlium/NifIo/blob/master/native/io/src/lib.rs
Some wip on the branch associated with #98
Didn't see much of a speed improvement when passing a ResourceArc around using an Agent
And we saw errors!
Problem statement
Calling the
Agent
in front of theMemtable
is slow. In fact, querying the:gb_tree
isn't the slow part... it's waiting for the agent process to respond that takes the bulk of the time under load!Is it possible to somehow hide the memtable behind a rust/NIF facade and speed up access to this large, shared structure?
Also see #97 -- perhaps there's some gain to be made by swapping out
Agent
forGenServer
.Simple plan
You could just create an elixir agent which exposes read-only state: the only thing it can do is give you a copy of a ResourceArc pointing to the rbtree.
Then use that Arc to mutate a Red Black Tree. Try using intrusive collections: rbtree to represent the memtable. For an easy test implementation, store all keys as strings and values as strings.
Some inspiration: https://github.com/Terkwood/rustler/commit/e944e6ee47fba1ac4a124cc21a93d1030641d9b9
Background
As load increases, the discrepancy gets worse: agent server-side is relatively stable while waiting for the process to respond to the client takes longer and longer amounts of time.
value_controller.ex
(client-side) section takes about ~10 units of timeInternal
Agent.get
only takes ~1 unit of timeTidbits on the web