Adding support for other runtimes to grammers-client?
Hi! Maintainer of compio here. As of now, grammers‑client only works with the tokio runtime annd I’d like to propose adding support for compio and potentially other async runtimes to it by adding a runtime abstraction and corresponding feature flags. If that sounds like doable I'm more than willing to open a PR for that.
My original desire was indeed to be as runtime-agnostic as possible. That conflicted a bit with the little time I have and other desire to make it work at all first.
If you're willing to help, that'd be really appreciated. Hopefully the only remaining tokio-centric part is the grammers-mtsender with the recent refactor (I am pushing to polish all crates, and have started from the bottom of the README diagram, with the sender and client missing from improved API and documentation review).
Just a remark but, any changes should aim to make the code runtime-agnostic, not explicitly add support (and the required maintenance) of two separate runtimes. I already had a recent situation where WASM support was unfortunately difficult to abstract enough and thus the cost too high for me to keep upstreamed here.
Hi. Thanks for responding. Runtime agnostic is always what we are trying to achieve with compio. I have attempted to create a runtime abstraction for grammers. However during the process I have encountered some design difficulties, with one major blocking problem on the IO design.
Compio uses what we call completion based io, like io_uring on Linux and IOCP on Windows. But the submit-and-wait nature requires programmers to give up their ownership on buffer when they want to do any IO, and that's what we do with compio-buf (buffer abstraction on what can be submitted into kernel) and compio-io (AsyncRead/Write that takes ownership of buffer). That means if we want to abstract over runtimes, we'd have to unify the IO interface in some way. A compatibility layer between tokio and compio (use tokio's AsyncRead/Write as the interface and adapt other runtimes to it) is certainly viable, but that would entail a shim buffer to be introduced, and hence runtime overhead. Another way is to use compio-io as the io interface. That means some refactor in net and fs module, when calling the io, read/write buffers need to be taken and send into kernel, with the benefit of no runtime abstraction (tokio's Async io interface can be seen as a subset of compio's). I want to stress that both compio-buf and compio-io are runtime agnostic. They don't depend on compio-runtime or compio-driver in any way. The sole purpose was to create an abstraction layer that anyone can use.
Other changes that need to be done, include:
- Replace tokio's mutex/mpsc with futures (or other options)
- Replace JoinSet with other runtime's alternative
- Replace tokio::select with futures::select
- sleep/spawn
I'm not sure if I covered all runtime usage, but I believe this is doable as seen in multiple libraries. One library that I worked on has a really nice runtime abstraction: https://docs.rs/openraft/latest/openraft/async_runtime/trait.AsyncRuntime.html, but they don't require lower level network access. They only need rpc-style network: https://docs.rs/openraft/latest/openraft/network/trait.RaftNetwork.html.
shim buffer to be introduced, and hence runtime overhead
I'd be OK with this. Top performance is not my top priority for grammers (it might be for others, but it is not for me; although of course I'm wary of not unnecessarily being inefficient.) Furthermore if compio uses io_uring, I'd expect that to perform better I/O-wise anyway (though certainly one would need to measure if some were to compare the two).
use compio-io as the io interface […] tokio's Async io interface can be seen as a subset of compio's
I'd also be OK with this if "tokio" could still be somewhat easily replaced by other runtimes…
I want to stress that both compio-buf and compio-io are runtime agnostic
…which seems like they would be. So it seems like this second option might be preferred.
I was not/am not worried about tokio disappearing any time soon, and it also seems like compio is quite active too. So it should also be fine on this front as well. (On the other hand, async-std also had a noble goal, and I did consider it when I created grammers, sadly it's now been discontinued. Such is the way of open source though.).
(I don't want to imply compio and its ecosystem won't succeed as a project, but it is still a possibility that could lead to additional maintenance work in the future, so I can't help but consider it.)
Lastly,
Other changes that need to be done
All sound fine, and regarding:
They only need rpc-style network: https://docs.rs/openraft/latest/openraft/network/trait.RaftNetwork.html.
That'd be similar to what grammers-client needs, right? Simply a way to send requests and get results without worrying about how that happens.