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

Relax RandomAccess type requirements, make all Read*|Write* methods work with non-seekable files #58381

Open
3 tasks
Tracked by #64596
adamsitnik opened this issue Aug 30, 2021 · 9 comments · May be fixed by #96711
Open
3 tasks
Tracked by #64596
Assignees
Labels
area-System.IO in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@adamsitnik
Copy link
Member

In .NET 6 we have introduced new type called RandomAccess that allows for reading and writing to specific file offset.

As of today, all it's Read* and Write* methods throw when given handle points to a non-seekable file like socket or pipe:

ThrowHelper.ThrowNotSupportedException_UnseekableStream();

But it's not a problem for it's internal implementation (used by FileStream):

// The Windows implementation uses ReadFile, which ignores the offset if the handle
// isn't seekable. We do the same manually with PRead vs Read, in order to enable
// the function to be used by FileStream for all the same situations.
int result = handle.CanSeek ?
Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset) :
Interop.Sys.Read(handle, bufPtr, buffer.Length);

And we use it's internal API surface to workaround this limitation is CoreLib (mind the call to RandomAccess.WriteAtOffset (internal), not RandomAccess.Write (public):

RandomAccess.WriteAtOffset(sfh, bytes, 0);

We should relax the public requirements and make RandomAccess work with non-seekable files.

This is going to require:

  • a breaking change doc
  • implementation change (stop throwing exception)
  • test changes (this test shows how to easily create a handle that points to non-seekable pipe)

Everything motioned above should be a single PR. In the same or separate PR, the Unix implementation of overloads that accept multiple buffers should start using readv and writev sys-calls. This should be relatively easy (just search for preadv and pwritev and reuse the patterns)

But it's going to allow to:

@adamsitnik adamsitnik added area-System.IO help wanted [up-for-grabs] Good issue for external contributors labels Aug 30, 2021
@adamsitnik adamsitnik added this to the 7.0.0 milestone Aug 30, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Aug 30, 2021
@ghost
Copy link

ghost commented Aug 30, 2021

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Issue Details

In .NET 6 we have introduced new type called RandomAccess that allows for reading and writing to specific file offset.

As of today, all it's Read* and Write* methods throw when given handle points to a non-seekable file like socket or pipe:

ThrowHelper.ThrowNotSupportedException_UnseekableStream();

But it's not a problem for it's internal implementation (used by FileStream):

// The Windows implementation uses ReadFile, which ignores the offset if the handle
// isn't seekable. We do the same manually with PRead vs Read, in order to enable
// the function to be used by FileStream for all the same situations.
int result = handle.CanSeek ?
Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset) :
Interop.Sys.Read(handle, bufPtr, buffer.Length);

And we use it's internal API surface to workaround this limitation is CoreLib (mind the call to RandomAccess.WriteAtOffset (internal), not RandomAccess.Write (public):

RandomAccess.WriteAtOffset(sfh, bytes, 0);

We should relax the public requirements and make RandomAccess work with non-seekable files.

This is going to require:

  • a breaking change doc
  • implementation change (stop throwing exception)
  • test changes (this test shows how to easily create a handle that points to non-seekable pipe)

Everything motioned above should be a single PR. In the same or separate PR, the Unix implementation of overloads that accept multiple buffers should start using readv and writev sys-calls. This should be relatively easy (just search for preadv and pwritev and reuse the patterns)

But it's going to allow to:

Author: adamsitnik
Assignees: -
Labels:

area-System.IO, up-for-grabs

Milestone: 7.0.0

@adamsitnik adamsitnik removed untriaged New issue has not been triaged by the area owner help wanted [up-for-grabs] Good issue for external contributors labels Aug 30, 2021
@adamsitnik adamsitnik self-assigned this Aug 31, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Sep 1, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Oct 12, 2021
@adamsitnik adamsitnik removed their assignment Oct 12, 2021
@deeprobin
Copy link
Contributor

@adamsitnik Whats the current state of this? Why is your PR closed?

@adamsitnik
Copy link
Member Author

Whats the current state of this?

It's still on my TODO list for 7.0.

@alexrp
Copy link
Contributor

alexrp commented Jul 13, 2022

@adamsitnik Is this likely to make it into .NET 7?

@jeffhandley
Copy link
Member

Unfortunately, we won't be able to get to this in .NET 7.0. We will consider it again during our .NET 8 planning.

@alexrp
Copy link
Contributor

alexrp commented Jan 6, 2024

What would it take to move this forward?

I've looked a fair amount at the RandomAccess/FileStream innards in the last few days, and this change honestly seems super straightforward. I could probably contribute a PR if the issue is allocating cycles to do the work.

Two potential problems I see are:

  1. I think this might need API review sign-off? It wasn't explicitly written, but it seems API review signed off on these methods throwing for non-seekable handles. Can someone confirm if this would be necessary?
  2. I'm not sure what bureaucracy/documentation around the breaking change aspect is needed (even if the break is fairly innocuous), and whether that's something that might be problematic if an external contributor does the work?

@adamsitnik
Copy link
Member Author

It would most likely be a matter of resurrecting #58506, solving merge conflicts and writing a breaking change doc.

It would be great to take a fresh look at https://github.com/dotnet/runtime/pull/58506/files#r701031142 and see whether it can be improved.

@adamsitnik
Copy link
Member Author

One of the main features of RandomAccess is thread-safety and ability to issue concurrent reads and writes. When we have offsets, it's easy: just do it for given offset. For non-seekable files, we would need to test the behavior and make sure that does what is expected and in the same way on Windows and Unix.

@adamsitnik adamsitnik self-assigned this Jan 9, 2024
@adamsitnik adamsitnik removed this from the Future milestone Jan 9, 2024
@adamsitnik adamsitnik added this to the 9.0.0 milestone Jan 9, 2024
@adamsitnik
Copy link
Member Author

I am going to send a PR for that.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 9, 2024
@adamsitnik adamsitnik modified the milestones: 9.0.0, 10.0.0 Jul 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.IO in-pr There is an active PR which will close this issue when it is merged
Projects
None yet
4 participants