-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
non-blocking versions of file open/stat #256
Conversation
16d9d6c
to
ecacadf
Compare
test failure should hopefully be addressed by #257 |
@swift-nio-bot please test |
1 similar comment
@swift-nio-bot please test |
@swift-nio-bot test this please |
ecacadf
to
af9d966
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor question, otherwise looks good.
Sources/NIO/NonBlockingFileIO.swift
Outdated
guard case shouldRun = BlockingIOThreadPool.WorkItemState.active else { | ||
p.fail(error: ChannelError.ioOnClosedChannel) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have a convenience wrapper around submit
that adds this boilerplate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proposed an API for that now.
af9d966
to
252339b
Compare
@@ -75,6 +75,8 @@ public final class BlockingIOThreadPool { | |||
|
|||
/// Submit a `WorkItem` to process. | |||
/// | |||
/// - note: This is a low-level method, in most cases the `submit` method should be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should presumably be runIfActive
, not submit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, thanks
252339b
to
f0d35ad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, let's let @normanmaurer review as well.
let promise: EventLoopPromise<T> = eventLoop.newPromise() | ||
self.submit { shouldRun in | ||
guard case shouldRun = BlockingIOThreadPool.WorkItemState.active else { | ||
promise.fail(error: ChannelError.ioOnClosedChannel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO using an ChannelError
here is a bit odd as the BlockingIOThreadPool
has nothing to do with a Channel
at all and we also have no reference to the Channel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@normanmaurer yes, that is indeed very odd. However that is what the other methods do so I copied it. Happy to fix but then we're slightly inconsistent...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm ok... We should have spotted this before :( I guess we need to fix this in a next major
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@normanmaurer well, we could just be different in this particular method. That wouldn't be breaking API as it's a new API. It would just behave slightly differently than the read
apis.
/// - eventLoop: The `EventLoop` to create the returned `EventLoopFuture` on. | ||
/// - body: The closure which performs some blocking work to be done on the thread pool. | ||
/// - returns: An `EventLoopFuture` fulfilled with the result (or error) of the passed closure. | ||
public func runIfActive<T>(eventLoop: EventLoop, _ body: @escaping () throws -> T) -> EventLoopFuture<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we maybe better just take the EventLoopPromise<T>
directly and not the EventLoop
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, unconvinced as there are more things that can go wrong if we ask the user to give us a promise instead of just making one. What's the benefit of taking a promise instead of the EventLoop
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The major benefit is that the user controls where the future fires. That's basically it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Lukasa but that's why I take the EventLoop
. I tell the user that the returned future will fired on the EventLoop
passed in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, basically isomorphic here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@weissi for me taking a EventLoop
looks more like running something on the EventLoop
, which is not the case here. Also taking an EventLoopPromise
is more consistent with what we do for ChannelOutboundInvoker
imho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also @Lukasa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, let @Lukasa be the tie breaker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think we should take a promise: it's more consistent with the other interfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
60f6164
to
64e7553
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy, waiting on @normanmaurer.
/// - promise: The `EventLoopPromise` that will be fulfilled when the block finished running (or failed). | ||
/// - body: The closure which performs some blocking work to be done on the thread pool. | ||
/// - returns: The `EventLoopFuture` of `promise` fulfilled with the result (or error) of the passed closure. | ||
public func runIfActive<T>(promise: EventLoopPromise<T>, _ body: @escaping () throws -> T) -> EventLoopFuture<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, probably. It's likely to be non-obvious that the Future
returned here is the one corresponding to the passed-in promise
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Lukasa and @normanmaurer can we please go back to taking the EventLoop
? It's important that we return an EventLoopFuture
as the next thing you want to do is clearly work with that file. The taking-the-promise approach is just a performance improvement if you might not care about the result of the operation (usually for EventLoopFuture<Void>
s). For opening files however we absolutely do care about the return value. So we will need a promise&future here and I still think we should take the EventLoop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Lukasa & @normanmaurer updated this guy
64e7553
to
7df910d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My previous +1 still applies.
@weissi please rebase, address conflicts and merge |
505ad73
to
388d576
Compare
@swift-nio-bot test this please |
@swift-nio-bot test this please |
Motivation: Opening a file, seeking it or querying its size (or other information) is blocking on UNIX so `NonBlockingFileIO` should support that too. Modifications: Added a method to `NonBlockingFileIO` which lets the user open a file without blocking the calling thread. Result: Less blocking is good :)
8e764e9
to
3b1a8e9
Compare
@normanmaurer / @Lukasa I'll merge this when the tests go green as we'll release a 1.5.0 very soon, okay? |
WFM. |
same... WFM |
addresses #185. This is a first draft to discuss the API.
Motivation:
Opening a file, seeking it or querying its size (or other information)
is blocking on UNIX so
NonBlockingFileIO
should support that too.Modifications:
Added a method to
NonBlockingFileIO
which lets the user open a filewithout blocking the calling thread.
Result:
Less blocking is good :)