Skip to content
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

Adopt NIOThrowingAsyncSequenceProducer #2879

Merged
merged 2 commits into from
Sep 13, 2024

Conversation

rnro
Copy link
Contributor

@rnro rnro commented Sep 10, 2024

Motivation:

Adopt NIOThrowingAsyncSequenceProducer in NIOFileSystem to reduce code duplication.

Modifications:

Adopt NIOThrowingAsyncSequenceProducer in NIOFileSystem DirectoryEntryProducer and FileChunkProducer

Result:

No functional changes. Internal changes reduce code duplication.

@rnro rnro requested a review from glbrntt September 10, 2024 14:23
@FranzBusch FranzBusch added the semver/patch No public API change. label Sep 11, 2024
Copy link
Member

@FranzBusch FranzBusch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general this looks good to me. Have you run some benchmarks between the two to make sure we still have the same performance?

Copy link
Contributor

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! I left a couple of small comments which need addressing.

@@ -135,52 +136,85 @@ extension DirectoryEntries.Batched.AsyncIterator: Sendable {}
// MARK: - Internal

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension BufferedStream where Element == [DirectoryEntry] {
extension NIOThrowingAsyncSequenceProducer where Element == [DirectoryEntry], Failure == Error,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
extension NIOThrowingAsyncSequenceProducer where Element == [DirectoryEntry], Failure == Error,
extension NIOThrowingAsyncSequenceProducer where Element == [DirectoryEntry], Failure == (any Error),

switch self.state {
case let .idle(handle, _):
return handle.threadPool
case let .open(threadPool, _, _):
return threadPool
case .openPausedProducing(let threadPool, let source, let array):
self.state = .modifying
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.modifying isn't required here because we aren't modifying any of the state held in the openPausedProducing case

internal mutating func pauseProducing() {
switch self.state {
case .open(let nIOThreadPool, let source, let array):
self.state = .modifying
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, no need to do .modifying

case .done:
return nil
case .modifying:
fatalError()
}
}

internal mutating func pauseProducing() {
switch self.state {
case .open(let nIOThreadPool, let source, let array):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: threadPool

Comment on lines 131 to 132
init(range: FileChunks.ChunkRange, handle: SystemFileHandle, length: Int64) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no blank lines at the start of funcs

Suggested change
init(range: FileChunks.ChunkRange, handle: SystemFileHandle, length: Int64) {
init(range: FileChunks.ChunkRange, handle: SystemFileHandle, length: Int64) {

Comment on lines 133 to 145
let state: ProducerState = switch range {
case .entireFile:
.init(handle: handle, range: nil)
case .partial(let partialRange):
.init(handle: handle, range: partialRange)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't think our minimum Swift version is new enough to support this? Also the indentation is way off for the body of each case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also I really don't like this syntax but maybe I'm just a curmudgeon...)


@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension ProducerState.Producing {
mutating func updateRange(count: Int) -> Bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not obvious how the range is updated without looking at the implementation, also the return value is quite misleading: if updateRange(count: blah) { ... } looks a whole lot like "if the range was updated then ...".

Would probably be clearer if you call this didReadBytes(_ count: Int) and documented the return value (you could use an enum for the return type but that's probably overkill)

@glbrntt
Copy link
Contributor

glbrntt commented Sep 11, 2024

In general this looks good to me. Have you run some benchmarks between the two to make sure we still have the same performance?

I would be surprised if there was a substantial difference. You'd think the syscalls would dominate here but it's worth doing some validation nonetheless.

@rnro rnro force-pushed the adopt_NIOThrowingAsyncSequenceProducer branch 4 times, most recently from 7d74670 to 41fe2de Compare September 12, 2024 15:58
Copy link
Contributor

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good modulo some failing CI!

case .produceMore:
self.produceMore()
case .stopProducing:
self.state.withLockedValue { state in state.pauseProducing()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.state.withLockedValue { state in state.pauseProducing()}
self.state.withLockedValue { state in state.pauseProducing() }

@rnro rnro force-pushed the adopt_NIOThrowingAsyncSequenceProducer branch from 41fe2de to b61146f Compare September 13, 2024 10:18
Motivation:

Adopt `NIOThrowingAsyncSequenceProducer` in NIOFileSystem to reduce code
duplication.

Modifications:

Adopt `NIOThrowingAsyncSequenceProducer` in NIOFileSystem
`DirectoryEntryProducer` and `FileChunkProducer`

Result:

No functional changes. Internal changes reduce code duplication.
@rnro rnro force-pushed the adopt_NIOThrowingAsyncSequenceProducer branch from b61146f to eac6c2a Compare September 13, 2024 10:48
@rnro
Copy link
Contributor Author

rnro commented Sep 13, 2024

Performance-wise there doesn’t seem to be much of a difference.

I tested listing the files on disk, exercising the DirectoryEntries path. I listed a directory I happened to have with 772492 files in it making up 23GiB.

For the existing code:
3 runs of: 27.51s, 26.53s, 26.34s
With an average of: 26.8s

For the new code:
3 runs of: 26.08s, 27.71s, 27.35s
With an average of: 27.05s

@rnro rnro merged commit 282f593 into apple:main Sep 13, 2024
27 of 29 checks passed
@rnro rnro deleted the adopt_NIOThrowingAsyncSequenceProducer branch September 13, 2024 13:21
ali-ahsan-ali pushed a commit to ali-ahsan-ali/swift-nio that referenced this pull request Sep 15, 2024
### Motivation:

Adopt `NIOThrowingAsyncSequenceProducer` in NIOFileSystem to reduce code
duplication.

### Modifications:

Adopt `NIOThrowingAsyncSequenceProducer` in NIOFileSystem
`DirectoryEntryProducer` and `FileChunkProducer`

### Result:

No functional changes. Internal changes reduce code duplication.
@finagolfin
Copy link
Contributor

This pull consistently causes hanging FileHandle tests in my Android CI, that runs them in an Android x86_64 emulator on both linux and macOS built with 5.10, 6.0, and trunk 6.1. I can reproduce locally on Android 13 AArch64 with a recently-built trunk 6.1 toolchain from the Sep. 4 source snapshot and the Termux 5.10.1 toolchain.

I'll see if I can track it down and file an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/patch No public API change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants