-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make API more idiomatic #90
Comments
The reason why the Filesystem trait in rust-fuse uses a Reply argument instead of returning is to allow for asynchronous response. If I'm understanding this feature request correctly, this would not be an improvement, but a setback :/. |
Maybe then return a Another problem is that you can call
with |
|
Hum, right XD |
If rust-fuse moves to I have some WIP stuff on integrating |
I'd also really like to see a more idiomatic API. Back when I wrote the Filesystem trait, it wasn't really clear how cases like these should be handled idiomatically. I like the idea to use
|
I've been thinking about how to make the API more idiomatic and have come up with some ideas. We need to keep ensured that (a) the actual implementation can only reply once to each request and (b) an error reply is sent if the implementation forgets to reply at all. A fs operation method currently looks like this: fn lookup(&mut self, _req: &Request, _parent: u64, _name: &OsStr, reply: ReplyEntry); This ensures (a) by passing the reply object which has self-consuming More idiomatic would be to return a result: fn lookup(&mut self, _req: Request, _parent: u64, _name: &OsStr) -> Result<ReplyEntry, Error>; Both (a) and (b) would be covered because the implementation must return exactly one result. Since This however might allow people to mistakenly create a wrong reply type and mess things up if they manage to interchange replies between different requests to satisfy the return type.
To make it asynchronous, we can use futures instead of results. However since Future is a trait, we would require the "impl traits" feature, which is only available in nightly rustc yet. fn lookup(&mut self, _req: Request, _parent: u64, _name: &OsStr) -> impl Future<Item=ReplyEntry, Error=Error>; Without impl traits, we need to box the returned type. This works with stable rustc, but would require an allocation for every returned value (!) fn lookup(&mut self, _req: Request, _parent: u64, _name: &OsStr) -> Box<Future<Item=ReplyEntry, Error=Error>>; We could either implement asynchronous operations in a different trait (which would end up in duplicating the large With futures, it's getting a little more complicated.. The Thoughts/ideas appreciated |
I still don't quite get why using return (without any explict async io crates [e.g. tokio] in the API) makes it impossible to perform async response... Does the function that calls these functions waits until these functions to return?
Any pointing to relevant code is appreciated. |
The point is that if it's passed as a parameter, the driver can then push the request/response to a thread pool or an event queue. |
The reply parameter doesn't make it async. The key thing is, that it doesn't prevent you from making it async. Passing the reply parameter gives the implementor freedom to either handle it asynchronously or synchronously.
That's also the reason why the function gets ownership of the reply parameter (it's moved into the function), it can pass it on to other threads. Providing the reply as return values would effectively prevent any async processing since the function would need to provide the reply value to finish. The internal kernel communication and dispatching is single threaded, so yes, the next operation can't be dispatched until the function returns. This design decision is quite old. I think there was no tokio or anything async back that time. There's some discussion about it in #1 :) However, using async in Rust still has a few drawbacks, e.g. async fns can't be used in traits yet and it still needs a nightly Rust to be compiled, so rust-fuse 0.4.0 will probably stay alpha/beta until futures in Rust become available in stable. |
(This is just for the period before async is fully integrated into rust. I agree using more native and explicit support is always better.) So, I mean, I see waiting for functions to return is a sequential operation. But the caller can always spawn a thread (or whatever async methods) and call this function in that thread (as well as performing any further work there, after the function call returns). I didn't dig into the detail of |
The caller of the
Not exactly. The reply type is crafted to be able to send the reply back to the kernel driver on its own. It doesn't get processed by an outer loop. |
I have some thoughts on an approach that could help make everyone happy. Firstly, keep the current interface. It's flexible for the reasons you stated, and works. The Second, let folks who want a fully synchronous API use Finally, handle async io by not handling it, and instead offering ways to serialize / deserialize the messages from a byte buffer. This "network protocols sans i/o" philosophy is the most flexible way to do this, in my opinion. And if you want to get fancy for async's sake, you could have it work with N byte buffers for vectored io. This is the design I'm going for with |
I did some cleaning and improvements on the code in the I'm in favor of making the API async (which can easily be done now by making every method async), however since Rust doesn't support async methods in traits yet, that'd mean to either use the Unfortunately, it would be hard to have both versions, a sync one and an async one at the same time. Making the trait async only if a certain feature is turned on seems a bit cumbersome. Easiest would be to change the return type to a boxed future of a reply, but that'd incur the cost of boxing the return value for each method call. Maintaining two filesystems traits, one with sync methods and one with async methods, seems too inconvenient as well. |
Basically: Look at the methods for the fuse-mt::FilesystemMT trait. Note how those methods have actual return values, rather than having the C-like "do something with some variable passed in as an argument and then return
void
" API that this crate currently has.I think changing this crate's API to be more like
fuse-mt
's would be an improvement.The text was updated successfully, but these errors were encountered: