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

More WriteGather fixes #109826

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

More WriteGather fixes #109826

wants to merge 13 commits into from

Conversation

adamsitnik
Copy link
Member

@adamsitnik adamsitnik commented Nov 14, 2024

  • don't run these tests in parallel, as each test cases uses more than 4 GB ram and disk
  • fix the test: handle incomplete reads that should happen when we hit the max buffer limit
  • incomplete write fix:
    • pin the buffers only once
    • when re-trying, do that only for the actual reminder
    • handle Int32 overflow on macOS

@adamsitnik adamsitnik added this to the 10.0.0 milestone Nov 14, 2024
@adamsitnik adamsitnik self-assigned this Nov 14, 2024
Copy link
Contributor

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

ReadOnlyMemory<byte> buffer = buffers[i];
totalBytesToWrite += buffer.Length;

MemoryHandle memoryHandle = buffer.Pin();
Copy link
Member Author

@adamsitnik adamsitnik Nov 14, 2024

Choose a reason for hiding this comment

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

So far, for incomplete writes we were pinning the memory for every retry attempt. I am not sure if this can create some kind of edge case bugs, but I think we can do it just once, before we enter the main loop

{
if (asyncMethod)
{
await RandomAccess.WriteAsync(sfh, writeBuffers, fileOffset);
bytesRead = await RandomAccess.ReadAsync(sfh, readBuffers, fileOffset);
Copy link
Member Author

Choose a reason for hiding this comment

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

this was a test bug, the test assumed that the read won't ever be a partial read

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

…o avoid the process getting killed on Linux when OOM happens)
@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

…th of all vectors overflows a 32-bit integer.
@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

{
break;
}
MemoryHandle memoryHandle = buffer.Pin();
Copy link
Member

@stephentoub stephentoub Nov 19, 2024

Choose a reason for hiding this comment

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

What happens if Pin throws an exception (or if the IReadOnlyList indexer does)? Won't we now leak all the previously created handles?

Copy link
Member Author

Choose a reason for hiding this comment

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

@stephentoub good catch, I forgot that the users can provide a custom MemoryManager and have Pin throw.

allowedCount = IOV_MAX;
totalLength += vectors[i].Count;

if (totalLength > INT_MAX && i > 0)
Copy link
Member

Choose a reason for hiding this comment

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

Why is the && i > 0 necessary? Can `vectors[i].Count be greater than INT_MAX in practice?

Copy link
Member Author

@adamsitnik adamsitnik Nov 19, 2024

Choose a reason for hiding this comment

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

Why is the && i > 0 necessary?

To avoid a situation where we pass 0 as iovcnt to the sys-call, it succeeds and the managed layer decides to continue the writes and ends up in an endless loop.

Can `vectors[i].Count be greater than INT_MAX in practice?

Not right now, as Memory.Length is an Int32 as of today.

@stephentoub is it worth to be so paranoid and defensive in your opinion?

Copy link
Member

Choose a reason for hiding this comment

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

Why is the && i > 0 necessary?

To avoid a situation where we pass 0 as iovcnt to the sys-call, it succeeds and the managed layer decides to continue the writes and ends up in an endless loop.

I'm not understanding. I thought this && i > 0 check was here to skip the first entry, but because Count can never be greater than INT_MAX, the totalLength > INT_MAX clause will never be true when i == 0.

I'm not clear on what this condition has to do with 0. If vectorCount is 0, we'll not be in this loop at all. And if Count is 0, either the totalLength would have already exceeded INT_MAX and would have been flagged by a previous iteration, or totalLength is not greater than INT_MAX.

I'm missing something. What? :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm missing something.

I expect that Count will be able to be more than Int32 one day. But most likely I am overthinking here.

Copy link
Member

Choose a reason for hiding this comment

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

I expect that Count will be able to be more than Int32 one day.

Ok. It'd be worth a comment, I think.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added an assert and removed the condition.

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adamsitnik
Copy link
Member Author

/azp run runtime-libraries-coreclr outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants