[ANN] riot 0.0.7 – an actor-model multi-core scheduler for OCaml 5

Hi folks :wave: we skipped over 0.0.6 because of a CI bug, and ended up releasing Riot 0.0.7 instead :slight_smile:

Here’s a summary of the changes.

Single public package

The public surface of the Riot package should be limited now to the top-level Riot module.

Introduce dedicated I/O Scheduler

To improve long-tail latency when doing I/O, we’re splitting out the poll loop out of the main schedulers and using a dedicated thread for polling I/O.

Improved I/O primitives

The runtime now ships with an IO and a Buffer module that includes more low-level functions:

  • to do vectorized reads/writes,
  • await for file descriptor availability (for reading, writing, or both),
  • copy data between buffers
  • write buffers directly to writers

I/O Readers & Writers

We’re introducing Reader/Writer to build Read/Write streaming pipelines like you’d do in Rust with the Read/Write traits.

This one is particularly exciting because we can now write super clean transformations of data that can be made super efficient, and are tracked at the type-level, like this:

let file = File.open_read "test" in (* [ `r ] File.t *)
let read = File.to_reader file in (*  [ `r ] File.t Reader.t  *)
let decrypt = Decrypt.of_reader read in (* [ `r ] File.t Decrypt.t Reader.t *)
let unzip = Unzip.of_reader read in (* [ `r ] File.t Decrypt.t Unzip.t Reader.t *)
let data (* IO.Buffer.t *) = 
  let buf = IO.Buffer.with_capacity 1024 in
  let* len = IO.Reader.read unzip ~buf in
  IO.Buffer.sub buf ~len
in
(* ... *)

This will pull 1024 bytes out of this stream, lazily reading backwards through the chain. And if you want it buffered, you just gotta call. IO.Reader.buffered reader and you’re good to go.

These new interfaces are available for the new File module as well as for the Net.Socket module.


And that’s 0.0.7 – you can read the much more terse full changelog here. The next release will include things like receive with timeouts, SSL support for sockets, and a few new high-level modules for working with processes!

If you try it out I’d love to hear what you think so don’t hesitate to reach out. I’m @leostera on x/discord.

Happy hacking! :camel:

12 Likes

Very cool!

One minor question/nit, wouldn’t you want to increment the minor version number for such feature releases? (https://semver.org/)

2 Likes

Before reaching 1.0.0, SemVer doesn’t really care too much what number is incremented. It’s really up to the project author.

2 Likes

Great work! Please, consider also adding something like {active, once} socket option in Erlang, so instead of blocking the current process on read it would send data when available via message passing.

1 Like

Thanks, TIL. The relevant section from SemVer:

Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

3 Likes

As @yawaramin says, we’re still at 0.y.z so it’s all unstable and exciting and in flux. Most likely we’ll go from 0.0.999 to 1.0.0 and THEN begin the SemVer work.

Until then, SemVer is overhead.

Thanks :pray:t3: We built something like this for the Twitch IRC chat client where we spawned a separate process that did the read from the socket stream and then parsed, so we received typed IRC commands. It was super nice.

I’m considering adding an “active mode” to a reader, so whatever reader stream you build you can turn it into a process and have it send you messages.

This is a more general solution than OTPs active mode sockets, but it could use some volunteers to see if it’s in practice more ergonomic, especially around the parsing.

Open to suggestions! :mailbox_with_mail:

1 Like