bgoosman

bgoosman

Attempt at adapting KuzuDB's Rust crate into Elixir via NIF, any tips/thoughts?

I got a very basic NIF working for KuzuDB: GitHub - bgoosmanviz/kuzu_nif: Adapting KuzuDB's Rust crate to Elixir using Rustler · GitHub.

KuzuDB is an embedded graph database, in the same sense sqlite is an embedded sql database.

Posting here in case anyone is interested in helping flesh it out. I don’t know Rust very well.

Most Liked

bgoosman

bgoosman

After 3 days of pain, I successfully added rustler_precompiled to kuzu_nif and published to hex.pm. Users of kuzu_nif on supported targets (see below) no longer need to compile the Rust crate.

Why? This saves us a few minutes on every build. For me, I’m using kuzu_nif in a Phoenix Framework project. Having a precompiled version of kuzu_nif means 1) I don’t need to install a Rust compiler in my Phoenix Framework dockerfile and 2) I save precious time compiling my Phoenix app.

The supported targets are indicated in the packaged release files. TLDR; Apple arm/x86 and Debian Linux arm/x64.

  • libkuzu_ex-v0.7.0-nif-2.17-aarch64-apple-darwin.so.tar.gz
  • libkuzu_ex-v0.7.0-nif-2.17-aarch64-unknown-linux-gnu.so.tar.gz
  • libkuzu_ex-v0.7.0-nif-2.17-x86_64-apple-darwin.so.tar.gz
  • libkuzu_ex-v0.7.0-nif-2.17-x86_64-unknown-linux-gnu.so.tar.gz

Figuring out how to successfully compile on aarch64 linux was the hardest part. In the end, I had to compile a custom Docker image just for building aarch64-unknown-linux-gnu.

Enjoy! :tada:

filmor

filmor

The thread creation stuff in enif only exists to provide a platform-independent API for threading in C. They don’t have (to my knowledge) any deeper “integration” with the BEAM.

One thing to keep in mind is that not all work has to happen in the actual NIF call. You can easily spawn a thread (or a pool of threads) and pass the PID of the caller that you then use to send the result of the query back to. This is what I use in my XML processing faster_xml/rust_src/faster_xml_nif/src/lib.rs at master · filmor/faster_xml · GitHub and it works fine in production, even without an actual thread pool.

So, simple suggestion to get started: Have a Database stored in a resource object, and on every query, spawn a thread that creates a Connection and sends the result back.

Later you can refine this to use a thread pool (with some retry logic on the Elixir side).

That way, the NIF will be quick enough that you don’t need to worry about scheduling and you get proper concurrent processing.

evnu

evnu

NIFs are executed by regular scheduled threads of the VM. See [the Erlang docs] (erl_nif — OTP 29.0.2 (erts 17.0.2)) for the big fat warning on long-running work, special care should be taken when a call takes more time than about 1ms. I usually just scheduled NIFs on an async scheduler (dirty CPU mostly) when the NIF was supposed to work for some longer time.

Note that Rustler doesn’t implement all of erl_nif, for example creating threads in the VM is not implemented as rust threads can be spawned if necessary.

Last Post!

bgoosman

bgoosman

To be fair to Rustler, I think my “unsafe interaction” was actually a bug on my part. I suspect my NIF was taking too long, so I’ve since added the “DirtyCpu” flag. By the time I made that change, I had already created kuzu_pyport_ex. Since I don’t need super high performance, I’ve already switched.

Where Next?

Popular in Questions Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New

We're in Beta

About us Mission Statement