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

ENH Rework streams handling #4035

Merged
merged 45 commits into from Aug 21, 2023
Merged

ENH Rework streams handling #4035

merged 45 commits into from Aug 21, 2023

Conversation

hoodmane
Copy link
Member

@hoodmane hoodmane commented Aug 3, 2023

This fixes a number problems with the old stream handling:

  1. Not possible to set a custom errno (necessary for proper interrupt handling and possibly for other things)

  2. Inefficient: in a lot of cases we have data in one buffer and we need it placed into a different buffer, but we have to implement a function that gets one byte out of the source buffer and then call it repeatedly to move one byte at a time to the target buffer.

  3. Ease of implementation: in many cases we already have perfectly good buffer manipulation APIs, so if we have direct access to the true source or target buffer we can just use these. See: the node IO code, which got much simpler.

This is backwards compatible, so you can still use the old input mechanism or use buffered or raw output. But it adds a new method of directly implementing read/write. For simplicity, we insure that the source/destination buffers are always Uint8Array views that point to exactly the region that is meant to be read/written. Because TypedArrays have support for views, I see no reason APIs should pass around a larger buffer with auxilary offset/length parameters.

If you do use the old mechanisms, they are still faster and can correctly support keyboard interrupts. Other than that I think the original behavior is unchanged. I added a lot more test coverage to help ensure that, since the streams tests I wrote before had pretty anemic coverage.

I think the read/write APIs are mostly pretty simple to use, with the exception that someone might forget to return the number of bytes read. JavaScript's ordinary behavior coerces the undefined to a 0, which leads to an infinite loop where the filesystem repeatedly asks to read/write the same data since it sees no progress. I added a check that writes an error message to the console and sets EIO when undefined is returned so the infinite loop is prevented and the problem is explained.

  • Add a CHANGELOG entry
  • Add / update tests
  • Add new / update outdated documentation

hoodmane and others added 30 commits August 3, 2023 10:46
This fixes a number problems with the old stream handling:

1. Not possible to set a custom errno (necessary for proper interrupt
   handling and possibly for other things)

2. Inefficient: in a lot of cases we have data in one buffer and we need
   it placed into a different buffer, but we have to implement a function
   that gets one byte out of the source buffer and then call it repeatedly
   to move one byte at a time to the target buffer.

3. Ease of implementation: in many cases we already have perfectly good
   buffer manipulation APIs, so if we have direct access to the true source
   or target buffer we can just use these. See: the node IO code, which got
   much simpler.

This is backwards compatible, so you can still use the old input mechanism
or use buffered or raw output. But it adds a new method of directly implementing
read/write. For simplicity, we insure that the source/destination buffers are
always Uint8Array views that point to exactly the region that is meant to be
read/written. Because TypedArrays have support for views, I see no reason APIs
should pass around a larger buffer with auxilary offset/length parameters.

If you do use the old mechanisms, they are still faster and can correctly support
keyboard interrupts. Other than that I think the original behavior is unchanged.
I added a lot more test coverage to help ensure that, since the streams tests I
wrote before had pretty anemic coverage.

I think the read/write APIs are mostly pretty simple to use, with the exception
that someone might forget to return the number of bytes read. JavaScript's ordinary
behavior coerces the `undefined` to a 0, which leads to an infinite loop where the
filesystem repeatedly asks to read/write the same data since it sees no progress.
I added a check that writes an error message to the console and sets EIO when undefined
is returned so the infinite loop is prevented and the problem is explained.
Makefile Outdated Show resolved Hide resolved
Copy link
Member

@ryanking13 ryanking13 left a comment

Choose a reason for hiding this comment

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

Thanks, @hoodmane and sorry for the late review.

I have a few minor comments, otherwise LGTM.

Makefile Outdated Show resolved Hide resolved
src/js/esbuild.config.mjs Outdated Show resolved Hide resolved
docs/conf.py Outdated Show resolved Hide resolved
docs/usage/streams.md Outdated Show resolved Hide resolved
docs/usage/streams.md Outdated Show resolved Hide resolved
src/js/streams.ts Outdated Show resolved Hide resolved
src/js/streams.ts Show resolved Hide resolved
src/js/streams.ts Outdated Show resolved Hide resolved
src/js/streams.ts Outdated Show resolved Hide resolved
src/tests/test_streams.py Outdated Show resolved Hide resolved
@hoodmane
Copy link
Member Author

Thanks for the detailed review @ryanking13!

@hoodmane hoodmane merged commit e19621d into pyodide:main Aug 21, 2023
21 of 22 checks passed
@hoodmane hoodmane deleted the streams-new2 branch August 21, 2023 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants