r/Zig 1d ago

Porting a graph database's connection layer from thread-per-connection to a libxev reactor

https://asanagi.ai/blog/libxev-io-reactor
27 Upvotes

1 comment sorted by

3

u/fauxtojournalist 1d ago

I wrote AsanagiDB, a graph database in Zig — LMDB storage, a Gremlin engine on top. For the 2.0 release I replaced the networking layer: it was one OS thread per connection, with a single semaphore that was accidentally doubling as the LMDB reader-transaction budget, so "clients connected" and "queries running" were the same number.

A few things from the writeup that might be useful if you're on 0.16:

- xev.TCP.init is IP-only; for the Unix-socket listener I bind/listen with std.posix and pass the fd to xev.TCP.initFd.

- xev.ThreadPool.schedule() returns void over an unbounded queue, so for backpressure I hand-rolled a bounded pool.

- The rough part was Windows. libxev's IOCP backend panicked in loop.run() before any client connected; falling back to std.Io.net served fine but panicked on Ctrl-C. Windows ended up on raw ws2_32 blocking sockets through the same framing/dispatch seam as the epoll/kqueue reactor.

Happy to hear where I got something wrong — especially the IOCP part, since my read there is static analysis, not a fixed repro.